金子です。


再び、文字列置換の話です。

2日前に次の2つの問題点を指摘しました。

  1) 置換文字列の最後に '\\' があるとき、文字列の終端を超えて
     1バイト余分に出力してしまう。

      => 終端の '\\' は加工せずにそのまま出力。

  2) '\\\\' が '\\' に置換されてしまう。

      => '\\\\' --> '\\\\' として出力。

1)は単純なコーディングミスと思われます。これは問題ないでしょう。
問題は 2) です。
これを perl では '\\\\' は '\\\\' となるし、これもコーディングミス
と思って、perl に合わせるように修正したつもりなのですが、どうも単純
な問題ではないような気がしてきました。

2)の修正を入れてしまうと、1バイトの '\' を正しく表現する方法がな
いような気がするのです。

これは perl では問題になりません。
perl はユーザの記述したテキストを置換時に1回だけ評価するためです。
'\\' のように '\' を重ねればそれは '\' 文字そのものを表します。

対して、ruby ではユーザ記述のテキストを通常の文字列オブジェクトに
するのに1回評価され、その後、置換する際にもう1回評価されます。
このとき、同じメタ文字 \ を別の意味で評価するため、いくつかの副作
用を生じます。
以下に例をあげます。
(この例は 2) の修正を入れたもの仮定してます。)

   a) 括弧に対応する後方参照 \1 をダブルクォーテーションで括る
      文字列中に埋め込む場合、"\\1" のように '\' を重ねて記述
      しなければならない。

   b) 最終的に \1 のような出力結果を得たいとき、簡単に記述する
      方法がない。
      '\\1'と記述すると後方参照と解釈されるし、'\\\1'と記述
      すると、\\1 のような出力結果となる。'\\\\1' でも \\1。
      "\x5c1" も後方参照。

   c) 変数を置換文字列として与えたとき、予期せぬ結果をうむことが
      ある。
      (DOSのディレクトリ名 C:\000\111 の処理など。)
      かつ、それを解決する簡単な手段がない。

現状の ruby では b) の問題はおきません。
"\\\\" と記述することで1バイトの \ に確実に変換できるためです。
また、c) についても 前処理で '\' を二重化してやることでとりあえ
ず回避できます。

# もちろん、イテレータを使えば何でもありは承知しています。

で、結局 ...

perl と違うし、直感的でもないのですが、現在の仕様は正解なので
しょうか?

直感的に、かつ、仕様をすっきりさせるためには、メタ文字を変えて
しまうとかしかないのでしょうか?

# 私の知らない置換文字列の特殊表記法があるっていうのでもいいのですが...


-- 
金子 尚史 (KANEKO Naoshi)   wbs01621 / mail.wbs.or.jp