Vimでパターン検索するなら知っておいたほうがいいこと

この記事はVim Advent Calendar 2012の166日目の記事です。
165日目はaueweさんによる.vimrcに書くべきでないVimの設定項目でした。

Vimに限りませんが、テキストエディタを使う際にテキスト検索はよく使うと思います。 ある程度慣れた人だと正規表現を用いたパターン検索を使うようになります。 もちろん、Vimにも正規表現を用いたパターン検索を行う機能は備わっています。 しかし、お世辞にもVimのデフォルト設定ではパターン検索は書きやすいとは言えません。 特に、他の正規表現方言に慣れている人は、Vim正規表現の書き方の違いに戸惑うと思います。 本記事では、Vimでパターン検索するなら知っておいたほうがいいこと+ Vimのパターン検索に使えるメタ文字をご紹介します。

パターンって何?という方は:help usr_27.txtを一読することをおすすめします。 一般的な正規表現について詳しく知りたい方は、ウェブや書籍などで一度しっかり勉強することをおすすめします。 ちょっと難しいですが、おすすめの書籍はサイドバーに載せてますのでご参考までに。

Vimでのパターン検索

Vim正規表現を用いたパターンは、検索コマンド/での検索、:subsutituteコマンド のパターン部分、:global:vglobalコマンドのパターン部分などで使うことができます。

他にもVim scriptの正規表現マッチ(=~,!~)や、いくつかの関数で使用出来ます。

ただ、オプションによってパターンで扱うメタ文字(正規表現として扱う特殊な文字、文字列)の指定の仕方に違いがあります。 オプション名はmagicで、現在のオプション値を確認するためには以下のようにコマンドを実行します。

:set magic?

デフォルトはmagicなので、おそらくmagicと表示されるはずです。

試しに検索コマンドでパターン検索をしてみましょう

以下は、0文字以上の任意の文字列にマッチするパターンです。

/.*

普段は.*だけでパターンを書くことはないと思いますが、一般的な正規表現ですね。

次は、fooかbarにマッチするパターンを入力してみましょう。

/\(foo\|bar\)

検索は出来ましたが、何か\でたくさん前置してますね。 そうなんです。Vimのデフォルトのmagicオプションでは、一部の特殊文字は、 \で前置しないとメタ文字として扱われません。

厄介なのが、メタ文字として扱うために前置する必要がある文字と、 前置が不要な文字が混在しているのです。

例えば、magicの場合、.,*,^,$\で前置しなくてもメタ文字として扱われますが、 (,),|,+,?\で前置しないとメタ文字として扱われません。

正直慣れていても、誤爆する事が多々あります。

要は慣れてないってことですねorz
特に+は鬼門。。。

very magicを使う

上記問題は、very magicを使うことで解消出来ます。 vim Hacksでも紹介があったのでご存じの方も多いと思います。

Hack #55: 正規表現のメタ文字の扱いを制御する

この機能を使うと、正規表現に使うすべての特殊文字\で前置せずに使えるようになります。 ただ残念ながらこの機能、set verymagicのようにオプションとして設定出来ません。 very magicを有効にするには、パターンを入力するところで\vと入力します。 すると\v以降がvery magicとして扱われます。 例えば検索コマンドでは以下の様に入力します。

/\v

very magicを有効にした状態でfooかbarにマッチする文字列を検索してみましょう。

/\v(foo|bar)

これで、パターン検索する際に(|)\で前置する必要はなくなりました。

他にも、+,?,{など、よく使う正規表現のメタ文字が\での前置なしで使えるようになります。

私はパターン検索を常用しており、毎回\vと入力するのが嫌なので、以下のようにキーマップを設定しています。

nnoremap /  /\v

これで大分Vimでのパターン検索がしやすくなりました。

Vimのパターン検索に使えるメタ文字

very magicで、パターン検索でのメタ文字の入力が楽になりました。 ただ、Vimのパターンはちょっとした方言があるので、よく使うメタ文字をまとめておきたいと思います。

わかりやすさのため使っている人が多いと思われるPerl正規表現方言との比較を載せます。 簡単な比較は:help perl-patternsに載っています。

ここでまとめるVimのメタ文字はすべてvery magicの指定を前提としており\で前置していませんのでご注意ください。 また、全てを網羅しているわけではないので、詳細が知りたい方は:help pattern-overviewで調べるといいです。 ただし、helpにはmagicnomagicしか載ってません。といってもvery magicは基本的にはmagicで 前置されている\をとるだけなのでhelpを見て困ることはないと思います。

Perlのメタ文字 Vimのメタ文字 説明 備考
. 同じ 任意の1文字
* 同じ 直前のアトムの繰り返し(0回以上) 最長マッチ
+ 同じ 直前のアトムの繰り返し(1回以上) 最長マッチ
? 同じ(=も同じ) 直前のアトム(0回、または1回) 最長マッチ
{n,m} 同じ 直前のアトムの繰り返し(n回以上m回以下) 最長マッチ
^ 同じ 先頭にマッチ
$ 同じ 末尾にマッチ
(...) 同じ グループ化してアトムにする
| 同じ 選択の区切り
[...] 同じ [...]内の任意の1文字にマッチ
\w 同じ 単語を構成する文字([0-9A-Za-z_])
\W 同じ 単語を構成する文字以外([\^0-9A-Za-z_])
\d 同じ 数字([0-9])
\D 同じ 数字以外([\^0-9])
\s 同じ 空白文字(微妙に違う。後述)
\S 同じ 空白文字以外(微妙に違う。後述)
*? {-} 直前のアトムの繰り返し(0回以上) 最短マッチ
+? {-1,} 直前のアトムの繰り返し(1回以上) 最短マッチ
?? {-0,1} 直前のアトム(0回、または1回) 最短マッチ
{n,m}? {-n,m} 直前のアトムの繰り返し(n回以上m回以下) 最短マッチ
\b < or > 単語の境界にマッチ(<は単語先頭、>は単語末尾)
(?=atom) atom@= 幅ゼロの肯定先読み
(?!atom) atom@! 幅ゼロの否定先読み
(?<=atom) atom@<= 幅ゼロの肯定後読み
(?<!atom) atom@<! 幅ゼロの否定後読み
(?>atom) atom@> 幅ゼロの否定後読み
(?:...) %(...) グループ化して部分正規表現としてカウントしない

その他Vim特有の便利なメタ文字

Vim特有で便利なメタ文字を紹介します。

メタ文字 説明 備考
\zs どこにでもマッチしてマッチの開始地点を設定する foo\zsbarとすればfoobarのbarの部分にマッチします
\ze どこにでもマッチしてマッチの終了地点を設定する foo\zebarとすればfoobarのfooの部分にマッチします
%[...] 任意にマッチするアトム列 r%[ead]とすれば'r','re','rea','read'にマッチします

PerlVim正規表現の意味が異なる主なメタ文字

PerlVimで意味が異なる主なメタ文字を紹介します。 他にもあるので、使用する際は、:help \xなどで調べてから 使用することをおすすめします。

メタ文字 Perl Vim
\s スペース、タブ(\t)、改行文字(\n)、復帰文字(\r)、フォームフィード(\f) スペース、タブ(\t)
\S 上記以外 上記以外
\b 単語境界 <BS>にマッチ
\B 単語境界以外 なし
\A 文字列の先頭 英字以外
\Z 文字列の最後 Unicodeの合成文字は無視

very nomagicを使う

very magicでメタ文字を入力しやすくなりましたが、\で前置が必要な文字がいっぱいあって、 メタ文字じゃなくてその文字自体を検索したい場合に困るという方は、 very nomagicを使うと便利です。

very nomagicはパターンを指定するところで、\Vと入力するとそれ以降の文字で すべての特殊文字\で前置が必須になります。 つまり\を検索したい場合だけ\\とすればよく、他の文字は\で前置せずに 検索することが出来るようになります。

例えば、very magicで入力していて、ここからは普通にテキスト検索したいと思ったら途中で \Vvery nomagicに切り替えることができます。 以下の様に入力します。

/\v(foo|bar)\V(foo|bar)

これは、fooかbarにマッチする文字列の後に(foo|bar)という文字列を検索という意味になります。

ちなみにデフォルトのmagic\m、他にもnomagicの指定は\Mと指定することで切り替えられます。 \v,\V,\m,\Mはやろうと思えば、パターン内で何度も切り替えられるので便利です。

エスケープが必要な文字

very magicだとすべての特殊文字が前置不要になるためその特殊文字自体に マッチさせたい場合は\でエスケープが必要になります。 また、very magicmagicnomagicvery nomagicと、それぞれエスケープが 必要な文字が異なります。

ここでは、very magicmagicnomagicvery nomagic のそれぞれでエスケープが必要な特殊文字(つまりその文字単体でメタ文字として扱われる文字)をまとめます。

very magicの場合

  • \
  • .
  • *
  • +
  • ?
  • =
  • {
  • ^
  • $
  • (
  • )
  • |
  • [
  • &
  • @
  • ~
  • /(検索コマンド/で検索する場合、/でパターンを囲う場合)

特に、=,&,@,~は、Perl正規表現方言ではメタ文字ではないのでハマりポイントです。

magicの場合

  • \
  • .
  • *
  • ^
  • $
  • [
  • ~
  • /(検索コマンド/で検索する場合、/でパターンを囲う場合)

nomagicの場合

  • \
  • ^
  • $
  • /(検索コマンド/で検索する場合、/でパターンを囲う場合)

very nomagicの場合

  • \
  • /(検索コマンド/で検索する場合、/でパターンを囲う場合)

おまけ

関連オプション

パターン検索に関連するオプションを紹介します。

" 大文字と小文字を無視する
set ignorecase
" 大文字と小文字を無視しない
set noignorecase

" 検索パターンが大文字を含んでいたら'ignorecase'を上書きする。('ignorecase'オンのときのみ使われる)
set smartcase
" 'ignorecase'を上書きしない
set nosmartcase

" メタ文字として扱う文字を`magic`で指定(`.`,`*`,`$`,`^`,`[`などを`\`で前置なしでメタ文字として扱う)
set magic
" メタ文字として扱う文字を`nomagic`で指定(`$`,`^`などを`\ `で前置なしでメタ文字として扱う)
set nomagic

Perlのplugin使う

Perl/Ruby方言の正規表現で検索、置換などができる eregex.vimというplugin があります。

ただ、eregex.vimインクリメンタルサーチができません。 何より、突然素のVimを使う必要に迫られた際や、 急に思い立ってVim scriptを書きたいと思った時にも、 Vim正規表現が使えなくて困るかもしれません。

なので、本記事ではインクリメントサーチが不要な方で、 どうしてもPerl/Ruby方言の正規表現じゃなきゃやだ! という方以外にはおすすめしません。

ちなみに私はPerl使い(というほどたいしたものでもありませんが。。。)なので、 しばらく、eregex.vimを使っていた時期がありました。 ただ、very magicを知ってからは、Vim正規表現もそんなに不便なく使えることがわかったので、 今はVimのパターン検索を使っています。

Vimのパターン検索で参考になるhelp

Vimのパターン検索は以下のhelpを参照するといいです。 本記事で書いたことはほとんどhelpに書かれていることです。

:help usr_27.txt
:help pattern.txt

まとめ

以上が、Vimでパターン検索する際に知っておくと便利なことでした。 正直ほとんどhelpに載っている話だったり、他の方が書かれた記事と変わらなかったりしますが、自分の整理のために書いてみました。
ちょっととっつきにくいだけでVim正規表現は普通に使えるのでちょこちょこ使ってVim正規表現に慣れていくことをおすすめします。

もしパターン検索について、こんなことも載せて欲しいとか、これも載せたほうがいいとかあれば、コメントやTwitterなどでご指摘いただけるとうれしいです。

あと、Vimのパターン検索に限りませんが、Vimレベルが上がるのでvimrc読書会に参加することをおすすめします。毎週土曜日23時からやってます。 次回(5/18)は大御所kanaさんのvimrcを読む予定です。すごいことになりそう。。。

それではVim Advent Calendar 2012の166日目を終わります。

明日のVim Advent Calendar 2012はyonchuさんです。