# \の影響

注：ブラウザや環境によって＼が￥に見えます。

- sub(gsub, sub!, gsub!)の引数

  - 第一引数に文字列を渡すのは止めましょう

    第一引数に文字列を渡すと

    1. 文字列のメタ文字の解釈(スクリプトコンパイル時)
    2. sub, gsub 実行時の正規表現へのコンパイル(正規表現のメタ文字の解釈)

    が順に行われ、混乱の元だからです。例えば

        p "foo".sub!("\\w+", 'bar') # => "bar"

    は、以下と同じです。

        p "foo".sub!(/\w+/, 'bar') # => "bar"

    シングルクォートを使っても

        p "\\".sub!('\\', 'bar') # => "bar"
        => -:1:in `sub!': invalid regular expression; '\' can't be last character: /\/ (RegexpError)

    などと混乱する場合があります。この例では正規表現 ``\`' をコンパイル しようとして失敗しています。以下が正解です。

        p "\\".sub!(/\\/, 'bar') # => "bar"

    ruby 1.7 feature: version 1.7 では、(2) は行われません。第一 引数に文字列を指定した場合、正規表現にコンパイルすることなく、文字 列をパターンとして探索を行います。(したがって、第一引数に関しての この注意は必要無くなります。)ただし、version 1.6 で

        Regexp.escape(文字列)

    を第一引数に指定している場合は、

        /#{ Regexp.escape(文字列) }/

    場合によっては(効率のために)

        /#{ Regexp.escape(文字列) }/o

    に書き換えるべきです。正規表現を渡すので、1.6、1.7 両方で同じ意 味になります。

  - 第二引数に \1, \2 などを渡すのは慣れないうちは止めましょう

    第二引数に文字列を渡すと

    1. 文字列のメタ文字の解釈(スクリプトコンパイル時)
    2. sub, gsub 実行時のメタ文字(\1, \2など)の解釈

    が順に行われ、混乱の元だからです。慣れないうちはブロックを使います。 (ブロックを使えば (2) は行われません)例えば

        p "foo".sub!(/(\w+)/, "\\1bar") # => "foobar"
        p "foo".sub!(/(\w+)/, '\1bar') # => "foobar"

    は、以下と同じです。

        p "foo".sub!(/(\w+)/) { "#$1bar" } # => "foobar"

    ブロックを使えば以下のようなこともできます。

        p "foo".sub!(/(\w+)/) { "#$1bar".upcase } # => "FOOBAR"

    ブロックを使わなければ sub! 実行前に upcase を行うので無効です。

        p "foo".sub!(/(\w+)/, "\\1bar".upcase) # => "fooBAR"

    第二引数はあくまでも短く書くためのものだと割り切った方が良いでしょ う。以下で何が行われてるのかヒト目でわかるような人は良いかも知れま せんが:p。

        p "\\".sub!(/(\\)/, "\1")       # => "\001"
        p "\\".sub!(/(\\)/, "\\1")      # => "\\"
        p "\\".sub!(/(\\)/, "\\\1")     # => "\\\001"
        p "\\".sub!(/(\\)/, "\\\\1")    # => "\\1"
        p "\\".sub!(/(\\)/, "\\\\\1")   # => "\\\001"
        p "\\".sub!(/(\\)/, "\\\\\\1")  # => "\\\\"
        p "\\".sub!(/(\\)/, "\\\\\\\1") # => "\\\\\001"

        p "\\".sub!(/(\\)/, '\1')       # => "\\"
        p "\\".sub!(/(\\)/, '\\1')      # => "\\"
        p "\\".sub!(/(\\)/, '\\\1')     # => "\\1"
        p "\\".sub!(/(\\)/, '\\\\1')    # => "\\1"
        p "\\".sub!(/(\\)/, '\\\\\1')   # => "\\\\"
        p "\\".sub!(/(\\)/, '\\\\\\1')  # => "\\\\"
        p "\\".sub!(/(\\)/, '\\\\\\\1') # => "\\\\1"

    この例で、メソッド p は ``\`' を ``\\`' と出力することにも 注意してください。

    さらに、以下のようなことはできないことにも注意してください

        p "foo".sub!(/(.*)/, "#{\\1}")
        # => -:1: compile error in string expansion (SyntaxError)

    式展開 `#{..}` の解釈はsub, gsub 実行前(引数解釈時)に行われます。こ の時点では `\1` は `\1` のままです。やはりブロックを使うの が正解です。

        p "foo".sub!(/(.*)/) { "#$1" }

link: [ruby 1.7 feature]
reverse links: [Rubyの落とし穴] [String]