Vimの置換

Vimの提供する機能で特に強力なものの1つに置換がある。前回と前々回で取り上げた検索と同じように、一致対象としてパターンを指定でき、置換後文字列に特別な文字列を使うことができる。シンプルな置換機能はどのエディタにもあることが多いが、複雑な置換をサクッと実行できるのはVimならではの特徴だ。

Vimの置換は強力である反面、指定方法が呪文じみている。慣れてしまえばどうということもないのだが、慣れないと本当に呪文のように見えるかもしれない。今回はこの置換について紹介する。

置換

Vimの置換はコマンドラインモードで実行する。ノーマルモードから入力する文字列の流れをシンタックス化すると次のようになる。[]は省略できる表記だ。

■Vim置換のシンタックス その1

:[範囲]s/パターン/置換後文字列/[フラグ] [処理行数]

■Vim置換のシンタックス その2

:[範囲]s/パターン/\=式/[フラグ] [処理行数]

「s」というのは「substitute (置換)」という英単語の頭文字だ。「s」ではなく「substitute」と入力しても同じように動作するが、長いので通常は「s」とだけ入力する。

置換後文字列の先頭が「\=」から始まっている場合、それ以降の記述は式として処理される。Vimはプログラミング言語としての側面も持っているのだが、要するに「\=」以降にプログラム的な書き方ができるようになるわけだ。こちらを使うとさらにいろいろ強力なことができるのだが、「少しでも運用管理を楽にしよう」という本連載の趣旨を鑑み、こちらの書き方については取り上げない。

範囲に関しても、ファイル全体に対して置換を実行するか、ビジュアル選択した範囲内で検索するかのどちらかだろう。そのため、基本的には次の2つの記述で置換を実行することが多くなる。

ファイル全体を置換

:%s/パターン/置換後文字列/g

テキスト選択の範囲内を置換

:'<,'>s/パターン/置換後文字列/g

ビジュアル選択について説明したときに触れたが、テキスト選択した状態で「:」キーを押すと「’<,’>」はVimによって自動的に入力される。つまり、ユーザーが入力する感覚としては次のようになっている。

テキスト選択の範囲内を置換(ユーザーの入力感覚)

:s/パターン/置換後文字列/g

なお、実際には「’<,’>」がないとカーソルがある行のみが置換処理の対象となるため注意が必要だ。以降では、それぞれの指定内容を説明する。

範囲指定

置換では「s」の前に範囲を指定する。何も指定しなければカーソルのある行のみが対象となり、「%」を指定すればファイル全体が対象となる。

範囲指定 内容
開始行,終了行 開始行から終了行までを範囲とする
カーソルのある行のみを範囲とする
% ファイル全体を範囲とする

開始行や指定行に指定できる内容は次のようになる。よくある使い方は「開始行番号,終了行番号」だが、パターンに一致する行から次のパターンに一致する行までとか、一致した行から5行後方の行から、といったような指定もできる。

行指定 内容
数字 行番号
. カーソルがある行
$ ファイル末尾行
% 1,$に同じ
‘< ビジュアル選択の開始行
‘> ビジュアル選択の終了行
/パターン/ パターンに一致する行(後方一致)
?パターン? パターンに一致する行(前方一致)
+数字 一致した行からさらに指定行数分後方へ移動した行
-数字 一致した行からさらに指定行数分前方へ移動した行

Vimではビジュアル選択が可能なので、ビジュアル選択してから「:s」と置換処理を行うことが多いのではないかと思う。複雑な範囲指定を行うこともできるが、ファイル全体かビジュアル選択の範囲か、その指定方法(操作方法)を覚えておけばよいだろう。

デリミタ

Vimの置換処理では「/」がデリミタとして使われることが多い。「:s/パターン/置換後文字列/g」のように指定を区切っている文字がデリミタだ。「/」がデリミタに使われている場合、パターンや置換後文字列に「/」を含めるには「\/」と指定する必要がある。そのため、ディレクトリパスやファイルパスなどを置換対象にすると、「\/」が高頻度で登場することになり、とても扱いにくい。

実は、デリミタは「/」である必要はない。「@」でも「+」でもよかったりする。シングルバイトキャラクタで英数字/バックスラッシュ/ダブルクォーテーション/パイプライン以外の文字をデリミタとして使用できるのだ。全て覚えておく必要はないが、「/」以外にも「@」や「+」がデリミタとして指定できる、といったことくらいを覚えておくとよいだろう。

デリミタを「@」にした場合

:%s@パターン@置換後文字列@g

デリミタを「+」にした場合

:%s+パターン+置換後文字列+g

パターン

置換で使えるパターンは、検索で使えるパターンと基本的には同じだ。以下に、そのパターンを掲載しておく。なお、検索について紹介していなかったパターンもいくつか追加している。置換ではそれらのパターンも使うことが多いからだ。

パターン 内容
^ 行頭(パターンの先頭でのみ指定可能)
$ 行末(パターンの末尾でのみ指定可能)
. 任意の1文字(行末には使用できない)
\%^ ファイルの先頭
\%$ ファイルの終了
\%V Visual領域の中
\%# カーソルの位置
\%’m マークm位置
\%数字l 指定行
\%数字c 指定列
\%数字v 指定仮想列
\_^ 行頭(パターンのどこでも指定可能)
\_$ 行末(パターンのどこでも指定可能)
\_. 任意の1文字(行末としても指定可能)
\< 単語の先頭
\> 単語の末尾
\zs 一致の開始を指定
\ze 一致の終了を指定
\^ ^
\$ $
. .
\e <ESC>
\t <TAB>
\r <CR>
\b <BS>
\n 行末
[] カッコ内に指定した文字のどれかに一致
\(\) グループ化
\1 1つ目の\(\)の中身に一致
\2 2つ目の\(\)の中身に一致
\3 3つ目の\(\)の中身に一致
\4 4つ目の\(\)の中身に一致
\5 5つ目の\(\)の中身に一致
\6 6つ目の\(\)の中身に一致
\7 7つ目の\(\)の中身に一致
\8 8つ目の\(\)の中身に一致
\9 9つ目の\(\)の中身に一致
\c 大文字小文字を区別せずに一致
\C 大文字小文字を区別して一致
\%d 10進数に一致
\%x 16進数に一致
\%o 8進数に一致
\%u マルチバイト文字に一致
\%U ラージマルチバイト文字に一致
\%C 合成文字に一致
\i 識別子文字
\I 識別子文字(数字は含まない)
\k キーワード文字
\K キーワード文字(数字は含まない)
\f ファイル名文字
\F ファイル名文字(数字は含まない)
\p 印刷可能文字
\P 印刷可能文字(数字は含まない)
\s 空白とタブ
\S 空白とタブ以外の文字
\d 数字([0-9])
\D 数字以外([^0-9])
\x 16進数([0-9A-Fa-f])
\X 16進数以外([^0-9A-Fa-f])
\o 8進数([0-7])
\O 8進数以外([^0-7])
\w 単語文字([0-9A-Za-z_])
\W 単語文字以外([^0-9A-Za-z_])
\h 単語の先頭文字([A-Za-z_])
\H 単語の先頭文字以外([^A-Za-z_])
\a アルファベット([A-Za-z])
\A アルファベット以外([^A-Za-z])
\l 小文字アルファベット([a-z])
\L 小文字アルファベット以外([^a-z])
\u 大文字アルファベット([A-Z])
\U 大文字アルファベット以外([^A-Z])
\_d 数字(行末を含む)
\_D 数字以外(行末を含む)
\_x 16進数(行末を含む)
\_X 16進数以外(行末を含む)
\_o 8進数(行末を含む)
\_O 8進数以外(行末を含む)
\_w 単語文字(行末を含む)
\_W 単語文字以外(行末を含む)
\_h 単語の先頭文字(行末を含む)
\_H 単語の先頭文字以外(行末を含む)
\_a アルファベット(行末を含む)
\_A アルファベット以外(行末を含む)
\_l 小文字アルファベット(行末を含む)
\_L 小文字アルファベット以外(行末を含む)
\_u 大文字アルファベット(行末を含む)
\_U 大文字アルファベット以外(行末を含む)
繰り返しパターン 内容
* 直前指定の0回以上の繰り返し(より長い方に一致)
\+ 直前指定の1回以上の繰り返し(より長い方に一致)
\= 直前指定の0回または1回の繰り返し(より長い方に一致)
\? 直前指定の0回または1回の繰り返し(より長い方に一致)
\{n,m} 直前指定のn回以上m回以下の繰り返し(より長い方に一致)
\{n} 直前指定のn回の繰り返し
\{n,} 直前指定のn回以上の繰り返し(より長い方に一致)
\{,m} 直前指定のm回以下の繰り返し(より長い方に一致)
\{} 直前指定の0回以下の繰り返し(より長い方に一致)
\{-n,m} 直前指定のn回以上m回以下の繰り返し(より短い方に一致)
\{-n} 直前指定のn回の繰り返し
\{-n,} 直前指定のn回以上の繰り返し(より短い方に一致)
\{-,m} 直前指定のm回以下の繰り返し(より短い方に一致)
\{-} 直前指定の0回以下の繰り返し(より短い方に一致)

特にパターンに()という表記が追加してある点に注目しておきたい。()の中に書いた文字列やパターンに対して、後方から参照を行うことができるというものだ。正規表現ではこうした機能は後方参照と呼ばれることが多い。パターン中でも後方置換を行うこともできるが、だいたいは置換後文字列から後方参照を行うことが多い。

置換後文字列

置換後文字列はすべてがリテラル文字列(特別な意味を持たずに文字としての機能しか持たない文字)ということではなく、いくつかの記述は特別な意味を持っている。次に代表的なものをまとめておく。

置換後文字列で使える特別な文字列 内容
& 一致したパターン全体に一致
\& &
~ 前の置換文字列に一致
\~ ~
\0 一致したパターン全体に一致
\1 1つ目の\(\)の中身に一致
\2 2つ目の\(\)の中身に一致
\3 3つ目の\(\)の中身に一致
\4 4つ目の\(\)の中身に一致
\5 5つ目の\(\)の中身に一致
\6 6つ目の\(\)の中身に一致
\7 7つ目の\(\)の中身に一致
\8 8つ目の\(\)の中身に一致
\9 9つ目の\(\)の中身に一致
<CR> 行を2つに分割。<CR>はCtrl-V Enterで入力する
\r 行を2つに分割。<CR>はCtrl-V Enterで入力する
\<CR> キャリッジリターン(Ctrl-M)を挿入。<CR>はCtrl-V Enterで入力する
\n <NL>を挿入。改行はしない
\b <BS>を挿入
\t <Tab>を挿入
\ \

特に&、~、\に注意だ。これら文字列が出てきたときにはリテラル文字としてではなく意味のある文字として機能するため、これを知らないと意図しない動作をすることになる。\1や\2は()の中身に一致する。この指定は結構便利なので覚えておこう。

フラグ

フラグは置換処理の挙動を変更するオプションのことで、代表的なところで次のようなフラグが用意されている。

フラグ 内容
c 置換ごとに確認。y (置換を実施)、l (置換の実施と置換の終了)、n (置換をスキップ)、ESC (置換を終了)、a (すべての置換を実施)、q (置換を終了)、Ctrl-E (スクリーンアップ)、Ctrl-Y (スクリーンダウン)
g 行に含まれるすべての一致対象を置換。このフラグを指定しなかった場合、行に含まれる最初に一致した対象のみが置換される
i パターンの大文字と小文字を区別しない
I パターンの大文字と小文字を区別する
n 置換を実行せずに一致する対象数を報告

これらのなかでもよく使うのは「g」だ。「g」を指定しないと、行ごとに最初に一致したものだけが置換対象になる。あえてそのように振る舞わせることもあるが、「g」を指定して全ての一致対象を置換するケースのほうが多いのではないかと思う。

処理行数

置換処理の記述の最後には、処理行数を指定することができる。これは、実際に処理する行数の最大値だ。例えば20行目から10行分だけ処理する、といった指定を行いたい場合に、この指定を使うことになる。処理行数を指定すると「指定範囲の最後の行から指定した行数分だけ処理する」という意味になる。場合によっては範囲指定よりも処理行数指定の方が飲み込みやすい方も多いかもしれない。この辺りは好みの問題なので、好きなほうを使っていただきたい。

その他の置換機能

Vimが提供している置換機能はこれだけではない。文字単位での置換や単語単位での置換、さらには指定できる内容も実際にはもっと多い。しかし、今回取り上げたようなことを覚えておけば、かなりのことはできる。検索パターンと同様に、最低限のパターンと置換後文字列のなかでも特別な意味のものだけを覚えておいて、後は必要に応じてそのつど、調べていけばよいだろう。ともかく使い慣れて、あまり考えなくても手が動くようになっていくことが大切だ。