LoginSignup
4
2

More than 5 years have passed since last update.

vimにはマッチするけどemacsにはマッチしないvimmer的正規表現

Last updated at Posted at 2017-10-18

vimで検索していたA氏はふと考えた。

vimとemacsの論争。
vimはモードの概念がある。
emacsはOSと呼ばれるほど多機能である。

vimは含むけどemacsは含まない行が欲しい!」

つまり、2行目だけを取り出したいとする。
まずは解答。

/\v^(.*vim)@=(.*emacs)@!.*$

必要なこと

  • vim使いである
  • 基本的な正規表現を知っている
    • ^.*[aiueo]$ が何をしているか理解できればOK
  • 検索時に\vを付け、verymagicを有効にする
    • いちいち(などをエスケープするのが大変なため

以降、/\vは省略。

本題

前にviがあるmにマッチさせる

肯定後読みを利用。
()でくくり、次に@<=を付ける。

(vi)@<=m

これで、手前にviがある場合のみmにマッチする。

たとえば、

vim
elvim

mにマッチ。

movie
emacs

mにはマッチしない。

よく使うパターンなので、\zsという書き方が用意されている(sstart)。

vi\zsm

前にviがないmにマッチさせる

否定後読みを利用。
=!に変えたら否定。

(vi)@<!m

cam
miv
emacs

mにはマッチするが、

vim

mにはマッチしない。

次にmが続くviにマッチさせる

肯定先読みを利用。
<がなくなり、マッチング対象の後ろに来た形。

vi(m)@=

これは、

vim
elvim

viにマッチ。

movie
elvis

viにはマッチしない。

これもよく使うので、

vi\zem

\zeで修飾できる(eend)。

次にmが続かないviにマッチさせる

肯定先読みの=!に変える。

vi(m)@!

vi
movie

にはマッチするが、

vim
elvim

viにはマッチしない。

vimを含む行にマッチさせる

ここからが本番。
web検索のようにand条件でマッチングさせたい場合。

^(.*vi)@=(.*m)@=.*$

ちょっと複雑だけど、肯定先読みがポイント。

最初の^を読み取ったら、(.*vi)のチェックが開始。
「なんちゃらvi」が含まれているかどうかをチェック。

その後、(.*m)のチェックが開始。
「なんちゃらm」が含まれているかどうかをチェック。

どちらの条件も満たしていたら.*$の部分にマッチ。

この条件では、

vim
elvim
movie

等、行全体にマッチ。

mac
emacs
elvis

にはマッチしない。

moviemviの位置が逆だが、問題なくマッチする。

vimを含む行にマッチさせる

今度はor検索。
複雑に考えず、基本的な正規表現だけで書く。

^.*(vi|m).*$

文字列中にvimがあるかどうかをチェックしているだけ。
vimが含まれていればいいので、

mac
movie
emacs
vim
vi
elvim
elvis

上記すべてにマッチする。

vimも含まない行にマッチさせる

vimを含む行にマッチさせる」を反転させたもの。

^(.*vi)@!(.*m)@!.*$

=!に替わっているだけ。

最初の^を読み取ったら、(.*vi)のチェックが開始。
「なんちゃらvi」が含まれないことを確認。

含まれなければ、(.*m)のチェックが開始。
「なんちゃらm」が含まれないことを確認。

両方の条件を満たしたら、.*$にマッチする。

editor

にはマッチするが、

mac
movie
emacs
vim
vi
elvim
elvis

のどれにもマッチしない。

なお、簡単に書けることは簡単に書く。
mが含まれない文字列は[^m]*で表現できるので、

^(.*vi)@![^m]*$

と書ける。

viがあるがmがない行にマッチさせる

ここまできたら今までの応用で、

^(.*vi)@=(.*m)@!.*$

と、vi側は肯定、m側は否定にすればいい。

vi
elvis

の行全体にマッチするが、

mac
movie
emacs
vim
elvim

にはマッチしない。

また、例のごとくmが1文字なのを利用して、

^(.*vi)@=[^m]*$

とも書ける。

終わりに

「vimの行だけ見たいんや、emacsは目に入れたくないんや!」というときは、
おもむろに、

/\v^(.*vim)@=(.*emacs)@!.*$

と入力しよう。

vimとemacsの論争。
vimはモードの概念がある。
emacsはOSと呼ばれるほど多機能である。

vimだけが含まれる2行目がハイライトされる。

行全体ではなくvimという単語だけが欲しいなら、

/\v^(.*emacs)@!.{-}\zsvim\ze.*$ " 最初のひとつ
/\v^(.*emacs)@!.*\zsvim\ze.*$   " 最後のひとつ

というマッチも可能。

……なお、これはvimじゃなくても肯定先読み、否定先読みができればOK。

たとえばPCREを利用した-Pオプションが使えるLinuxのgrepでは、

$ grep -P -r '^(?=.*\Walias\W)(?=.*\Wls\W).*$' # \W は単語区切り

とやれば、「lsに対してaliasを設定している行だけ」を抽出できる。
まるで検索エンジン!

$ grep -rhv 'emacs' | grep 'vim'
$ sed -n '/vim/p' **/* | sed '/emacs/d'

とかはシェル芸に踏み込んでしまうのでここまで。

言い忘れていたけれど、私はemacs好きですよ。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2