このウェブログの本文で使っていた半角カッコを全角カッコに変えたくなった。文章校正的な理由ではなく、将来の縦書き化を見据えて今のうちに調節しておこうかなという程度の理由だ(半角カッコに戻すのは簡単そうだ、ということもある)。だが単純な置換ではなかなか難しく、手作業でやろうかと思ったが開き半角カッコだけで8000近くあったので無理そう……ということで一時間くらい色々考えた結果、ASCII範囲外の文字を含む開き半角カッコと閉じ半角カッコのペアを探して置換するのがよさそうという結論に至った。

Perlの正規表現ならばかなりかっこよく書けそうだったが、ファイル探索から読み込み、置換、保存まで書くのはさすがに面倒そうだ。普通にVimでqfreplaceを使って行うようにした。

:%s/(\(.*[^!-~ ].\{-}\))/(\1)/gc

Vimの正規表現なので気持ち悪いやつになっている。ASCII範囲外の文字はアバウトに!から~と半角スペースを指定して反転するというアバウトなものにした。これで大抵のプログラム・コードでの半角カッコはスキップすることができる。問題は半角カッコのネストと同じ行に半角カッコを使うコードが複数回出てくるパターン(「`foo()`や`bar()`」というようなパターンだと「()`や`bar()」にマッチしてしまう)だが、うろ覚えのVimの正規表現では考慮するのが厳しく、そこはcフラグも付けて手作業で行うことにした。

だいたいうまくいったのではないかと思う。後処理として()といった全角カッコに半角空白がついてしまっているパターンから半角空白を削除しておいたりもした。

本当はHTML断片としてパースして、codepre要素の子ではないものを置換するという、HTMLから見て真っ当なやり方がベストに近そうだ。しかしHTML断片をパースするためのライブラリーの選定を始めとして、書き捨てになりそうなコードを書くには面倒極まりないので、雑な正規表現で誤魔化した。なんでもエクセルでやる人の気持ちがちょっとわかった。


qfreplaceが同じファイルに複数の置換対象があると「既に変更があります」的なエラー・メッセージを出してスキップするようになった気がする。前は普通に動いていたので、最近のVimになって発症したのではないかと思うが、たまにしか使わないので何かVimの設定に依存しているのかもしれない。そのうち調べよう。