From: TAKAHASHI Masayoshi Date: 2001-09-25T18:11:33+09:00 Subject: [ruby-list:31599] Re: sub の動作 高橋征義です。 Shigeo OHUE さん: > >:文字列から正規表現で引っ掛けて「\&」に置換したいんですがうまく > >:できません。たとえば下のようになっちゃいます。 (略) > 何でそうなるかはまだわかりませんが、これから勉強します。 んでは、「何でそうなるか」について、解説してみます。 # 間違いがあったらご指摘ください(_o_) 要点は3つあります。 a) 「\」という文字は、「""」の中でも「''」の中でも特別な意味を 持ちます。 要するに「\」はエスケープ文字なので、自分自身をエスケープ することができなければなりません。 「"\\"」「'\\'」という文字列リテラルは、「\」という文字列に なります。 b) 「''」の中で、「\」の後ろに「\」か「'」以外の文字が来たときは、 「\」+その文字、になります。 つまり、「'\$'」は「\$」という文字列に、「'\a'」は「\a」という 文字列になります。 ここで気をつけた方がいいのは、「'\\$'」と「'\$'」が同じに「\$」に なってしまう、ということです。「'\\$'」では「\」がエスケープされ ているわけですね。 「\\$」という文字列が欲しい場合は、「'\\\$'」または「'\\\\$'」と 書かなければなりません。 # どちらかというと、「'\\\\$'」と「\」を4つ書くのがいいような # 気がしますが、どうなんでしょうね。 c) 「\&」という文字列は、subの第2引数の中では、「マッチした文字列と 同じ文字列」の意味になります。これを避けたい場合、つまり「\&」と いう文字列そのものに置換した場合は「\\&」という文字列を使う必要が あります(「"\\&"」でも「'\\&'」でないのに注意!)。 #!/usr/bin/env ruby replace_str = '\\&' p "012abc".sub(/a/, replace_str + replace_str) #=> "012aabc" 「マッチした文字列」というのは「a」なので、replace_str + replace_str は「a」+「a」、つまり「aa」になります。 これを踏まえた上で、実際の置換例を見てみましょう。 | irb(main):001:0> "a".sub(/a/, '\$') | "\\$" これは、/a/にマッチする最初の文字列を「\$」という文字列に置換する ことになりますが、「\$」には特殊な意味はないので、そのまま「\$」に なります。これを「""」で括られた文字列リテラルの形で表示すると、 「"\\$"」になります。 | irb(main):002:0> "a".sub(/a/, '\&') | "a" これも、/a/にマッチする最初の文字列を「\&」という文字列に置換する ことになります。ところが、「\&」は「マッチした文字列と同じ文字列」と いう意味になるので、マッチした文字列、つまり「a」で置換することに なります。 ということは、「a」を「a」で置換するので、結果もやはり「a」になります。 | irb(main):003:0> "a".sub(/a/, '\\\\&') | "\\&" 「'\\\\&'」は、「\」のエスケープが2回行われている、ということで、 「\」+「\」+「&」、つまり「\\&」という文字列になります。これで、 ようやく/a/を「\&」に置換できることになります。 ……判りましたか? やっぱり判りにくいですよね?(^^;; というわけで、私としても、ブロックを使うことをお勧めします。 # 長々と書いて結論がコレかい!……というのは言わない約束です(汗 高橋征義 (TAKAHASHI Masayoshi) Email:maki@inac.co.jp