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

时间:2010-10-07 16:59:48

标签: regex vim

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

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

:g/.*Carter\&.*Clinton\&.*Obama/p

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

:g/.*Carter\&\(.*Clinton\|.*Bush\)/p

(肯定有更好的方法)

但是我无法想象如何搜索(我看了相关的问题),例如,布什和克林顿不是卡特,更不用说如何搜索,例如布什和克林顿(卡特或奥巴马)。

2 个答案:

答案 0 :(得分:50)

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

例如,“不是布什”将是:

^\(.*Bush\)\@!

或使用\v

\v^(.*Bush)@!

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

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

\v^(.*Bush)&(.*Clinton)&(.*Carter|.*Obama)@!

附录

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

One&Two&Three

可以与:

互换
(One)@=(Two)@=Three

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

答案 1 :(得分:14)

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

g/^\%(.*\%(Carter\|Obama\)\)\@!\%(.*Bush\)\@=.*Clinton/

或者,非常神奇:

g/^\v%(.*%(Carter|Obama))@!%(.*Bush)@=.*Clinton/

请参阅:h /\@=

关于内在逻辑:前瞻就像分支:正则表达式(reg1)@=reg2假设reg2匹配位置N(匹配从位置N开始),正则表达式引擎检查reg1是否也匹配此位置。如果没有,则丢弃该位置,并且正则表达式引擎尝试下一次reg2的匹配。负面前瞻也是如此,但正如reg1 匹配时,正则表达式引擎会丢弃该位置。


示例:

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

字符串:aba

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