Rubyのソース中のダブルクォート文字列をシングルクォートに置換する(その2)

id:eel3:20090727:1248625974 に関して、vim正規表現での改行の取り扱いについてありがたいおつげ助言を頂いた。

:help /\_

そもそもこの手の問題は正規表現でざっくりは処理できても正確には処理できない。

Re: Rubyのソース中のダブルクォート文字列をシングルクォートに置換する - 新・日々録 by TRASH BOX@Eel - while ("im the true Vim master"); - vimグループ

……やっぱり基本はヘルプファイルか。ただ私は英語も第二外国語もNGなヘタレなので*1vimの日本語訳ヘルプファイルをググってpattern.txtでgrepしたのだった。ちなみにこのヘルプはvim 7.2用。

案の定というか何というか、マッチングで改行を含む含まないの辺りはvimでも手を入れている部分らしい*2。通常のメタ文字では改行にはマッチングしないけど*3、先頭に「\_」を付けることで改行にもマッチングするようになるメタ文字が色々とある模様。

ということで、Rubyエスケープ文字や簡単な式展開を含むダブルクォート文字列にマッチする正規表現に手を入れて、「改行を含む簡単な式展開」でも何とかなるようにしてみた。

:%s/"\(\(#{\_[^}]*}\|\\.\|[^"]\)*\)"/'\1'/gc

「\_[^}]」で「'}'以外の改行を含む文字」にマッチさせているだけなので、相変わらず{}が入れ子になっているようなケースでは失敗するはず。でもこんなのでも、

"#{user["name"]
# "user-name"
"user-name"}"

この程度の文字列には何とかマッチする。まあ、基本的に改行とか「式展開を含む文字列」を含む式展開って書かない気がするので*4、この程度でも十分だろう。

ところで、『入門vi 第6版』を持っている私は拡張正規表現の「\n」の存在を知っていた訳で、

:%s/"\(\(#{\([^}]\|\n\)*}\|\\.\|[^"]\)*\)"/'\1'/gc

なんて無理やり書くこともできたはず……だったのだけど、その存在を今の今まですっかり忘れていた。

それはともかく、やっぱり前回自分で自分につっこんだように、

正規表現の挙動についてあまり理解していないのが敗因だと思う。

という点が致命的だな、と思う。正規表現とツールに関する理解度が低いことで、「1つの正規表現でどこまでできるか」について正しい判断を下せていないという自覚がある。

これはアレか、『詳説 正規表現 第2版』と『詳説 正規表現 第3版』のどちらも積読状態になっている私に対する「いい加減どちらか読んどけ」という天の声だろうか?

*1:そもそも日本語すら怪しい。

*2:「改行も含む」マッチングができると便利な時もあるので、拡張されてるかもしれないとは思っていた。でも調べるのが面倒で放置してた。

*3:多分、viとの互換性の為。

*4:文法的にOKでも、可読性に欠けるからなあ。