Vimの置換は”沼”

Vimの置換機能はとても強力だ。前々回と前回で、置換機能の最も基本となる部分と、ぜひ覚えておきたいパターンについて取り上げた。しかし、前回までに取り上げた機能はVimの置換機能のほんの一部に過ぎない。Vimの”沼”たる由縁はここにあるのだが、機能を組み合わせることでもっと複雑な作業も一発で置換処理することができる。

そこまで複雑な処理は本連載の目的から外れてくるので取り上げないが、それでもちょっと足を突っ込むくらいのところまでは紹介しておきたいと思う。何せ強力なので、覚えておくと便利なことが多いからだ。今回は行をまたぐ置換処理について説明する。

Markdownの”方言”を変換してみよう

人気の高いテキストフォーマットにMarkdownがある。Markdownには”方言”も多く、いくつかの書き方がある。例えばタイトルを表現する方法は、タイトルの行の先頭にマークを追加する方法と、タイトルの行の次の行に下線の要領で線を入れるような書き方をする方法などがある。

【先頭にマークを追加する方法】

## タイトル

【下線を引く方法】

タイトル
--------

処理系によってはこのどちらかの表記に統一する必要がある。その場合に活躍するのが置換処理なわけだが、上記のように下線を引くスタイルは2行で表記している。置換処理の対象が2行、つまり行をまたぐパターンが存在するのだ。

次のテキストはMarkdownの方言の1つで、タイトルの表記は先頭にマークを追加する方法になっている。

Markdown方言表記テキストのサンプル

この表記を下線を引くタイプへ変換したり、またはその逆の変換を行ったりをVimの置換機能を使ってやってみよう。

行をまたぐ置換:1行→2行

行をまたぐ置換で、マークを使う方法から下線を引くタイプへ変換するのは比較的簡単だ。

マークを引く方法を下線を引くタイプへ置換する場合

上記サンプルでは「:%s/^## (.*)$/\1^M—————————/g」のように置換処理を実行している。置換対象は行先頭が「## 」のようになっているもので、置換後の文字列として「## 」以降の文字列+改行+「—————————」が指定されている。置換を実行すると次のようになる。

置換実行後

ポイントは置換後文字列に含まれている「^M」という表記だ。これは「Ctrl-V ↩️」のように入力した結果であり、「改行する」という指定になっている。ターミナルアプリケーションによってはショートカットキーが異なるかもしれないが、だいたいはこのやり方で入力できるはずだ。このように指定することで、置換結果を複数行に展開することができる。

行をまたぐ置換:2行→1行

Vimでは複数行を置換の対象として結果的に1行にまとめるという処理も簡単に実施できる。

下線を引くタイプからマークを使う方法へ置換する場合

上記サンプルでは「:%s/^(.*)\n—-*$/## \1/g」のように置換処理を実行している。置換対象は「文字列」+「改行」+「—-(略)」のようになる。置換後の文字列は「## 文字列」のようになり、置換を実行すると次のようになる。

置換実行後

ポイントは置換対象に含まれている「\n」という表記だ。この表記は改行に一致するようになっている。つまり、「\n」を含めておけば複数行にまたがる処理を実行することができるわけだ。先ほどは同じような指定が「^M」だった。この2つの表記は複数行を処理する上で便利なので覚えておこう。

もっと複雑に書くこともできる

Vimでは上記のような処理をもっと複雑な方法で命令することもできる。対象となる文字列で行を絞り込み、その行の前後に対して置換処理や削除処理行うのだ。それをさらにファイル全体に対して適用する、といった命令にすれば、一発で処理させることができる。しかし、上記で説明したように改行そのものを置換対象/置換後文字列に含めることができるので、かなりシンプルに置換処理を書くことができる。

複数行にまたがる置換は面倒に思われがちだが、Vimを使うと簡単に実現できる。今回取り上げた方法も便利なので、ぜひとも覚えておいてもらえればと思う。