Vim-Regex负面表情唤醒和捕捉组



假设您有以下文本

foobar
bar

你想要以下作为你想要的输出

foobar
foobar

您可以使用以下regex

s/v(foo)@<!(bar)/foo2/g

我之前犯的错误是认为bar的背面参考是1而不是2;我不认为regex环视被认为是一个捕获组。现在,我感兴趣的是,如果您使用1。您将得到以下输出

foobar
foo

使用上述逻辑,如果1指的是第一个捕获组(foo),那么我预计输出将是

foobar
foofoo

经过一点思考,我怀疑这个问题的答案是,由于它是一个正在使用的负面后备,它只在指定的文本foo不存在时捕获。因此,这意味着存储的捕获组什么都不是。只是一个空字符。如果1是指定的反向引用,这将导致foo是输出。我的推论正确吗?

让我对这一点相当确定的是,如果我要更改正则表达式,使用一个正的lookbacking,而不是引用第一个捕获组,如下

s/v(foo)@<=(bar)/foo1/g

然后输出将变为

foofoo
bar

这意味着,由于其为后备,当存在foo时,捕获组(foo)匹配,因此存储的捕获组必须是foo

造成这种混乱的原因是,Perl正则表达式的工作方式是正则表达式查找表被而不是作为捕获组包含。如果我在上面所说的是正确的,我很好奇为什么vim-regex和Perl-regex之间有这种区别。

我很好奇为什么vim regex和Perl regex之间有这种区别。

因为它们是两个不同的正则表达式引擎。如果它们以完全相同的方式工作,就不会有Vim正则表达式引擎和Perl正则表达式引擎,它们都将是Perl正则表达式发动机。

在某个时刻™,Vim制作了一个正则表达式引擎,并决定了某些事情。其中之一,显然是包括lookahead作为捕获组。如果您想进一步讨论与Perl的差异,@<=在Vim中允许非固定宽度模式,但在Perl(和其他几个引擎)中不允许。它就是这样设计的。";为什么";只有制作它的人才能明确回答,所以我不会回答这个问题。


如果您绝对想将该组从组计数中排除,您可以根据:h /%()%加前缀,使其成为非捕获组(即s/v%(foo)@<!(bar)/foo1/g)。请注意,非捕获组的行为仍然像正常情况一样,但在替换时不能引用它们。

虽然我已经在写答案了,但让我向您介绍zsze,这是迄今为止对Vim正则表达式引擎最好的添加之一(在我看来):

zs定义了实际匹配的起始位置。它不会影响群体,但有几个副作用。特别是在你的情况下,它可以让你完全放弃积极的观望。它不会让你放弃负面的查找(因为regex),但它会让你稍微简化你的regex。等效地,ze确定匹配在哪里结束。

您的第二个示例可以简化为:

s/vfoozs(bar)/1

zs告诉引擎在(bar)之前开始比赛。如果有帮助的话,您可以将每个regex看作前缀为zs,后缀为ze——明确定义它只会更改这些边界。这不影响号码分组和<n>保存。

这意味着只有bar选择的空间被认为是匹配的,并且该位被替换——其他位保持不变。

您的第一个带有负查找的正则表达式也没有简化(因为正则表达式总体上感觉是用于正向操作的,所以任何反向操作都会很混乱),但对于较长的正则表达式,它仍然可以显著缩短正则表达式。这是替代品的样子:

s/v(foo)@<!zebar/foo

扩展:

s/v
| (foo)@<!
| |       ze
| |       |   bar
| |       |   |  /foo
^ Very magic  |  |
^ not prefixed with foo. Can be made non-capturing, but it has no actual relevance for this regex specifically
^ End the match
^ bar
^ substitute the "area" selected by "not prefixed with foo" with foo

(因为这个糟糕的图表,我以前从来没有做过,我也不记得它们通常是如何制作的)

这一个使用ze,因为你的目标是间接地用自己来替换负面前瞻分配的空间。不幸的是,Vim只存储实际匹配的值,这意味着1不能用于插入foo,因为它还不存在。这可能是所有引擎都会做的事情,因为您无法猜测实例的(?<=ab.d)的内容。


也就是说,如果你只是想避免与组编号混淆,那么现在应该采用不捕获组的方式。zsze虽然很棒,但一开始有点令人困惑,暂时可能不是在Vim中学习其他一切的最佳主意。

最后,一个意想不到的插件推荐:haya14busa/incsearch.vim(没有隶属关系,只有一个用户),它可以预览你的替换和搜索,这样你就可以在进行替换或搜索之前知道会发生什么。这可能无助于解决你对组号的困惑,但在你替换之前,你至少可以看到你使用了错误的组号。

最新更新