Vim Regex:如何搜索A和B NOT C

ThG*_*ThG 49 regex vim

我有很多行包含美国总统卡特,布什,克林顿,奥巴马的名字.一些包含其中一个名称,一些包含2个,一些包含3个,其中一些包含所有4个(以任何顺序排列).

我知道如何寻找卡特和克林顿以及奥巴马 - >

:g/.*Carter\&.*Clinton\&.*Obama/p
Run Code Online (Sandbox Code Playgroud)

我知道如何寻找卡特和(克林顿或布什) - >

:g/.*Carter\&\(.*Clinton\|.*Bush\)/p
Run Code Online (Sandbox Code Playgroud)

(肯定有更好的方法)

但我无法想象如何搜索(我看了相关的问题),例如,布什和克林顿不卡特,甚至更少搜索,例如,布什和克林顿不(卡特奥巴马).

Pi *_*ort 52

要表示NOT,请使用否定断言\@!.

例如,"不是布什"将是:

^\(.*Bush\)\@!
Run Code Online (Sandbox Code Playgroud)

或使用\v:

\v^(.*Bush)@!
Run Code Online (Sandbox Code Playgroud)

重要提示:请注意领先^.虽然如果你只使用正断言(一个匹配与其他匹配一样好)是可选的,但是需要锚定负断言(否则它们仍然可以在一行的末尾匹配).

翻译"布什与克林顿而不是(卡特或奥巴马)":

\v^(.*Bush)&(.*Clinton)&(.*Carter|.*Obama)@!
Run Code Online (Sandbox Code Playgroud)

附录

为了解释之间的关系\&\@=:

One&Two&Three
Run Code Online (Sandbox Code Playgroud)

可互换:

(One)@=(Two)@=Three
Run Code Online (Sandbox Code Playgroud)

唯一的区别是\&直接镜像\|(应该更加明显和自然),而\@=镜像Perl (?=pattern).


ZyX*_*ZyX 14

如果你想在vim之后使用Perl风格的正则表达式,请忘记\&:它是一个vim特有的功能,因为vim也有前瞻功能,所以任何r1\&r2都可以重写为\%(r1\)\@=r2.但是前瞻性更好,因为它有一个负面版本,它们也可以在大多数Perl风格的正则表达式引擎中使用.您(Bush AND Clinton AND NOT (Carter OR Obama))可以通过以下方式表达:

g/^\%(.*\%(Carter\|Obama\)\)\@!\%(.*Bush\)\@=.*Clinton/
Run Code Online (Sandbox Code Playgroud)

或者,非常神奇:

g/^\v%(.*%(Carter|Obama))@!%(.*Bush)@=.*Clinton/
Run Code Online (Sandbox Code Playgroud)

看到 :h /\@=

关于内部逻辑:前瞻就像分支:对于正则表达式(reg1)@=reg2假设reg2匹配位置N(匹配从位置开始N),正则表达式引擎检查是否reg1也匹配此位置.如果没有,则丢弃该位置,并且正则表达式引擎尝试下一次可能的匹配reg2.同为负前瞻,但与正则表达式引擎丢弃如果位置的差异reg1 确实匹配.


例:

正则表达式:(.b)@!a.

字符串:aba.

  1. 找到匹配:a匹配位置0(aba).尝试匹配前瞻:.匹配a(aba)和b匹配b(),前瞻匹配,丢弃位置.aba
  2. 位置1()不匹配.abaa
  3. 找到匹配:a匹配位置2().尝试匹配前瞻:matches (),但不匹配:没有符号,前瞻失败.结果:正则表达式匹配位置2.aba.aabab