[ruby-list:48670] Re: "a_b$c" を "a\_b\$c" に変換したいのですが、、、

From: dezawa <dezawa@...>
Date: 2012-03-29 00:22:06 UTC
List: ruby-list #48670
okkez さん,信岡さん ありがとうございます
> 
> どうすればよいかは okkez さんが示されていますが、なぜそうなるのか
> 簡単に説明を。
> 
> String#gsub の第 2 引数では、「\&」 でマッチした文字列を表したり
> 「\1」 で最初のキャプチャ文字列を表したりできるわけで、バックスラッシュに
> 特別な意味があります。 そのため、単なるバックスラッシュを表したい場合には
> バックスラッシュを 2 つ連続させる必要があります。

これは知っていたので、 \\ で \ に、 \& でマッチ部分に、
ということで行けるかと思ったのですが、\ 5つですか。

 (1)ソース上の '\\\\\\&'  が読み込まれて '\\\\&' になり
 (2)コンパイルのときに  '\\&' になって
 (3)gsub 実行時に \\ が \ に & がマッチ部分に

ということなのかな。
(2)のステップをイメージしていませんでした。一つ利口になれました。
ありがとうございます。

あれ、、、違うみたいだな、
   puts "a_b$c".gsub(/[_$]/, '\\ \&') 
や
  puts "a_b$c".gsub(/[_$]/, '\&\\')
だと \\ で \ になる。
やはり \ は難しい。わからん。

> (ただし、バックスラッシュと後ろの文字の組み合わせが特に意味を
> もたない場合は、単一のバックスラッシュでもバックスラッシュと
> して認識されるみたいです。)

これはマニュアル通りですね。
 シングルクォートで囲まれた文字列では、 \\ (バックスラッシュそのもの)
 と \' (シングルクォート) を除いて文字列の中身の解釈は行われません。

gsub をブロックで受ける方法は再認識しました。
これもマニュアルでは目に入ってましたが素通りでした。
ややこしくなったらこれを使うことが良さそうですね。
ありがとうございます。

############
PS
シングルクォートに囲まれた連続する \ の扱いが、単なる文字リテラル
ではマニュアル通りですが、sub,gsub の replace ではおかしくなって
居る様です。
irbだとreadlineでのエスケープ処理が絡んでくる恐れも
あるか、とfileにして実行してみました。ruby 1.9.3p125です

puts"a_b$c".gsub(/[_$]/,'\\\\\\&')    # 8 => a\_b\$c
puts"a_b$c".gsub(/[_$]/,'\\\\\&')     # 9 => a\_b\$c
puts"a_b$c".gsub(/[_$]/,'\\\\&')      #10 => a\&b\&c
puts"a_b$c".gsub(/[_$]/,'\\\&')       #11 => a\&b\&c
puts"a_b$c".gsub(/[_$]/,'\\&')        #12 => a_b$c

puts"a_b$c".gsub(/[_$]/,"\\\\ \&")    #13 => a\ &b\ &c
puts"a_b$c".gsub(/[_$]/,"\\\ \&")     #14 => a\ &b\ &c
puts"a_b$c".gsub(/[_$]/,"\\ \&")      #15 => a\ &b\ &c
puts"a_b$c".gsub(/[_$]/,"\ \&")       #16 => a &b &c

puts"a_b$c".gsub(/[_$]/,'\\\\ \&')    #17 => a\ _b\ $c
puts"a_b$c".gsub(/[_$]/,'\\\ \&')     #18 => a\ _b\ $c
puts"a_b$c".gsub(/[_$]/,'\\ \&')      #19 => a\ _b\ $c
puts"a_b$c".gsub(/[_$]/,'\ \&')       #20 => a\ _b\ $c

マニュアルには
 シングルクォートで囲まれた文字列では、 \\ (バックスラッシュそのもの)と
 \' (シングルクォート) を除いて文字列の中身の解釈は行われません。

とありますが、その通りになっていないように思われます。
puts '\\\\\\\\' などような単純な文字リテラルの時は 
\\ => \ の期待通りになっていますが、
sub や gsub の replace の時の扱いがおかしいです。
  puts"a_b$c".gsub(/[_$]/,'\\\ ')   # => (1)a\ b\ c
  puts"a_b$c".gsub(/[_$]/,'\\\\')   # => (2)a\b\c
  puts"a_b$c".gsub(/[_$]/,'\\\\\ ') # => (3)a\\ b\\ c
  puts"a_b$c".gsub(/[_$]/,'\\\\\\') # => (4)a\\b\\c
  puts"a_b$c".gsub(/[_$]/,'\\\\\\ ')# => (5)a\\ b\\ c

マニュアル通りなら各々下の様になるのでは?
a\\ b\\ c、a\\b\\c、a\\\ b\\\ c、a\\\b\\\c、a\\\ b\\\ c


In This Thread