正規表現置換の練習ドリル5問
:s///の基本形は使えても、グループ参照や大文字小文字変換を組み合わせたパターンになると、実行結果を正確に予測できるか怪しくなる人も多いはずです。5問の予測ドリルで正規表現置換の感覚を確かめてください。:s以外も含めた置換の4つのやり方から確かめたいときは、そちらを先に読むと迷いません。
表記のルール:コマンドを実行する前のテキストを示し、実行後どうなるかを予測してから答えを確認します。
目次(10項目)
問題1
次のテキストに対して:s/\(\d\d\)\/\(\d\d\)/\2\/\1/を実行すると、どうなりますか。
Date: 03/08
答えを見る
\(...\)でグループ化した「03」と「08」を、置換後の文字列側で\2(2番目のグループ)→\1(1番目のグループ)の順に入れ替えて出力します。月日の並び順を逆にする置換です。
Date: 08/03
問題2
次のテキストに対して:s/\(.*\)/\U\1/を実行すると、どうなりますか。
hello world
答えを見る
\(.*\)で行全体をグループ化し、置換後の文字列で\Uを使うと、それ以降の文字列(\1で参照した部分)がすべて大文字に変換されます。
HELLO WORLD
問題3
次のテキストに対して:%s/\<./\u&/gを実行すると、どうなりますか。
the quick brown fox
答えを見る
\<.は各単語の先頭1文字にマッチします。置換後の\u&は、マッチした文字(&はマッチ全体を表す)の最初の1文字だけを大文字化します。結果として各単語の頭文字が大文字になります。
The Quick Brown Fox
問題4
次のテキストに対して:s/foo\zsbar/baz/を実行すると、どうなりますか。
foobar and foobaz
答えを見る
\zsは「ここから実際のマッチ開始位置とする」という指定です。パターン全体は「foobar」にマッチさせつつ、実際に置換される範囲は\zsより後ろの「bar」だけになります。「foo」は残ったまま「bar」だけが「baz」に変わります。
foobaz and foobaz
問題5
次のテキストに対して:s/,\s*/\r/gを実行すると、どうなりますか。
apple, banana, cherry
答えを見る
,\s*はカンマとその直後の任意個の空白にマッチします。置換後の文字列\rは改行を挿入する特殊な指定で、カンマ区切りのテキストを1行1項目に分割します。
apple
banana
cherry
\1/\2、大文字小文字変換の\U/\u、マッチ開始位置を調整する\zsを覚えると、置換パターンの表現力が一気に広がります。
\zsを知らなかった頃は、部分置換のためにグループ参照を使った長いパターンを書いていましたが、\zsを覚えてからは「マッチはさせたいが置換したくない部分」を素直に書けるようになり、パターン自体がずっと短くシンプルになりました。
予測が外れたときに見るところ
置換の結果が読めなくなる原因は、だいたい3つのどれかに収まります。1つ目は、パターン側の記号を打ち消し忘れているか、逆に余計に打ち消していることです。Vimの既定では ( や + は文字そのものを指し、グループや繰り返しにしたければ \( \+ と書きます。
2つ目は \U や \L の効き始める位置です。これらは指定した場所から後ろ全体に効き続けるので、途中で止めたいときは \E を書きます。3つ目は g フラグの有無で、付けなければ各行の最初の1か所しか置き換わりません。
パターンの打ち消しが多くて読めないときは、先頭に \v を付けると他の言語に近い書き方になります。:%s/\v(\w+)_(\w+)/\2_\1/ のように、バックスラッシュの数がかなり減ります。
実行する前に当たり具合を数える
いきなり置換して u で戻すより、先に何か所当たるかを数えたほうが安全です。フラグに n を付けると、置換せずに件数だけを返します。手元のVim 9.1.1752で foo を3か所含む2行のファイルに対して実行すると、3 matches on 2 lines と表示され、中身は変わりませんでした。
:%s/foo/X/gn " 3 matches on 2 lines (置換はしない)
:%s/foo/X/gc " 1か所ずつ確認しながら置換する
想定より件数が多ければパターンが広すぎ、少なければ打ち消しか大文字小文字の指定を疑います。件数を見てから gc に切り替える、という順番にすると、範囲の広い置換でも事故りません。
同じ置換をもう一度かける
置換コマンドは . では繰り返せません。代わりに & を押すと、直前の置換を今いる行にもう一度かけられます。フラグも含めて繰り返したいときは :&&、ファイル全体にかけ直すなら :%&& です。
範囲を少しずつ広げながら試すときに効きます。まず1行で試し、思ったとおりなら :%&& で全体に広げる、という進め方なら、失敗しても戻す範囲が小さくて済みます。より実践的な置換の使い分けは:substituteの活用集にまとめています。
まとめ
正規表現置換はグループ参照・大文字小文字変換・\zsのような特殊指定を組み合わせることで、単純な文字列置換では対応できない変換までカバーできます。基本形からもう一歩踏み込んだパターンは:substituteコマンド活用集もあわせて参照してください。出題の元になっている:substituteの書き方そのものは活用集に、検索パターン側の練習は正規表現検索のドリルにあります。