Regex Vim正则表达式负环视和捕获组
我将试着用一个例子来解释我的问题 假设你有下面的文本Regex Vim正则表达式负环视和捕获组,regex,vim,regex-lookarounds,regex-group,neovim,Regex,Vim,Regex Lookarounds,Regex Group,Neovim,我将试着用一个例子来解释我的问题 假设你有下面的文本 foobar bar 您希望以下内容作为所需的输出 foobar foobar 您可以使用以下正则表达式 s/\v(foo)@<!(bar)/foo\2/g 使用上述逻辑,如果\1引用第一个捕获组,(foo),那么我希望输出是 foobar foofoo 在考虑了一点之后,我怀疑这个问题的答案是,因为它是一个正在使用的反向查找,所以它仅在指定的文本foo不存在时捕获。因此,这意味着存储的捕获组什么都不是。只是一个空字符。如果\1
foobar
bar
您希望以下内容作为所需的输出
foobar
foobar
您可以使用以下正则表达式
s/\v(foo)@<!(bar)/foo\2/g
使用上述逻辑,如果\1
引用第一个捕获组,(foo)
,那么我希望输出是
foobar
foofoo
在考虑了一点之后,我怀疑这个问题的答案是,因为它是一个正在使用的反向查找,所以它仅在指定的文本foo
不存在时捕获。因此,这意味着存储的捕获组什么都不是。只是一个空字符。如果\1
是指定的反向引用,则这将导致输出为foo
。我的推断正确吗
让我对此相当确定的是,如果我将regex改为使用积极的lookback,而不是引用第一个捕获组,如下所示
s/\v(foo)@<=(bar)/foo\1/g
这意味着,由于它是一个正向查找,所以当存在foo
时,捕获组(foo)
匹配,因此存储的捕获组必须是foo
造成这种混乱的原因是Perl正则表达式的工作方式是不将正则表达式lookarounds作为捕获组包含。如果我在上面所说的是正确的,那么我很好奇为什么vim正则表达式和Perl正则表达式之间存在这种差异
我很好奇为什么vim正则表达式和Perl正则表达式之间存在这种差异
因为它们是两个不同的正则表达式引擎。我不完全理解您对这里的答案的期望,但是如果它们以完全相同的方式工作,就不会有Vim正则表达式引擎和Perl正则表达式引擎,它们都是Perl正则表达式引擎
在某个时候™, Vim制造了一个正则表达式引擎,并决定了某些事情。显然,其中之一就是将长相头作为捕获群体。如果您想进一步讨论与Perl的差异,@
虽然我已经在写一个答案,但让我向您介绍\zs
和\ze
,这是迄今为止Vim regex引擎的最佳补充之一(我有偏见地认为):
\zs
定义实际匹配的开始位置。它不会影响群体,但有几个副作用。特别是在您的情况下,它可以让您完全放弃积极的回顾。它不会让你放弃消极的回顾(因为正则表达式),但它会让你简化一点正则表达式。等效地,\ze
确定匹配的结束位置
您的第二个示例可以简化为:
s/\vfoo\zs(bar)/\1
\zs
告诉引擎在(条形)
之前开始匹配。如果有帮助的话,您可以将每个正则表达式看作前缀为\zs
,后缀为\ze
——显式定义它只会更改这些边界。这不会影响号码分组和保存
这意味着只有由条选择的空间被视为匹配,该位被替换,其他位保持不变
您的第一个具有负向后看的正则表达式也不会简化(因为正则表达式总体上感觉是用于向前操作的,所以任何向后操作都会变得混乱),但对于较长的正则表达式,它仍然可以显著缩短正则表达式。以下是这种替代的情况:
s/\v(foo)@<!\zebar/foo
s/\v(foo)@
扩大:
s/\v
|(富)@
(‘根据这张糟糕的图表,我以前从未做过一张,我不记得它们通常是怎么做的)
这一个使用\ze
,因为您的目标是间接地用自身替换由负前瞻分配的空间。不幸的是,Vim只存储实际匹配的值,这意味着\1
不能用于插入foo
,因为它还不存在。这可能是所有引擎都会做的,因为你猜不到(?)的内容?
s/\vfoo\zs(bar)/\1
s/\v(foo)@<!\zebar/foo