我有很多行包含美国总统卡特,布什,克林顿,奥巴马的名字。一些包含其中一个名称,一些包含2个,一些包含3个,其中一些包含所有4个(按任意顺序)。
我知道如何搜索卡特和克林顿以及奥巴马 - >
:g/.*Carter\&.*Clinton\&.*Obama/p
我知道如何搜索卡特和(克林顿或布什) - >
:g/.*Carter\&\(.*Clinton\|.*Bush\)/p
(肯定有更好的方法)
但是我无法想象如何搜索(我看了相关的问题),例如,布什和克林顿不是卡特,更不用说如何搜索,例如布什和克林顿(卡特或奥巴马)。
答案 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
。
a
匹配位置0(aba
)。尝试匹配前瞻:.
匹配a
(aba
)和b
匹配b
(aba
),前瞻匹配,丢弃位置。aba
)与a
不匹配。a
匹配位置2(aba
)。尝试匹配前瞻:.
匹配a
(aba
),但b
不匹配:没有符号,前瞻失败。结果:正则表达式匹配位置2。