使用Vim正则表达式匹配方括号时无法匹配成功

4
使用vim,我正在尝试将以下两行转换
  output reg [1:0] abcd,
  output reg efgh,

转换为

abcd
efgh

我正在使用正则表达式,

:%s/\voutput|reg|\s*|\[.*\]|,//g

但是,我得到的输出是:
[1:0]abcd,
efgh,

感谢您的帮助!谢谢。

奇怪的结果。尝试使用s/.* (\w+),/$1/g(或者在vim中你如何引用捕获组)。 - Qtax
我将保持这个问题的开放,因为我想了解为什么问题中提到的正则表达式无法工作。 - Rakesh
你可以将你的正则表达式 (\voutput|reg|\s*|\[.*\]|,) 插入到像 http://www.regexper.com/ 这样的网站中进行可视化。 - ajp15243
@Rakraks,正则表达式在PCRE和类似的语言中运行良好,例如http://regex101.com/r/vR8tB7。为什么它在vim中无法工作我不知道。 - Qtax
6个回答

4

:help pattern会给出原因(虽然从先前接触不同可能性中猜测原因非常有帮助)。

1. 模式是一个或多个分支,由"\|"分隔。它匹配与其中一个分支匹配的任何内容。例如:"foo\|beep"匹配"foo"且匹配"beep"。如果有多个分支匹配,则使用第一个分支。

Vim的正则表达式匹配器是一种首次匹配引擎。POSIX规范要求最左最长。纯粹主义者可能会认为其他任何东西都不是正则表达式匹配器,而只是“模式匹配器”,这可能与vim将它们称为“模式”有关... sedperl都是最左最长的:

$ sed -r 's/output|reg|\s*|\[.*\]|,//g' @@
abcd
efgh

$ perl -ple 's/output|reg|\s*|\[.*\]|,//g' @@
abcd
efgh

但使用第一匹配引擎,您需要稍微有些不同的操作。重新排列您的备选项,就能起作用:

:%s/\voutput|reg|\[.*\]|,|\s*//g

\s*替换为\s+可以使其不受顺序影响:

:%s/\voutput|reg|\s+|\[.*\]|,//g

Vim的g标志似乎会替换仅第一个匹配分支的每个出现,然后重试,直到没有更改。

为了完整和混淆,

:%s/\v(reg|output|\s*|\[.*\]|,)*//

abcd,
efgh,

并且

:%s/\v(reg|output|\s*|\[.*\]|,)*//g

abcd
efgh

考虑以上推导出的规则,这个瞬间对我来说是有意义的。

(编辑:据称 gawkgensubnviextended 引擎也是最左最长匹配方式)


3

试试这个

\v\[.*]\s+|output\s+|reg\s+

谢谢,我尝试了下面的代码,它可以工作。但是,我仍然不明白为什么我在问题中使用的正则表达式不起作用。%s/\v[.]\s|output|reg|,|\s*//g - Rakesh
因为你在]后面有空格,我猜你在]前面加了一个斜杠。 - i100

3
$xbd0

这个任务可以在一行完成。您可以记录宏,自动将其分成多行。


1
你的正则表达式中的问题在于你要求\s*。这意味着“零个或多个空格”。由于整个正则表达式是一个大的或,因此Vim将开始消耗您的字符串,直到找到至少一个空格。当发生这种情况时,它将从OR的开头开始匹配并重复该过程。因此,这意味着您尝试在\s*之后接收任何表达式都将被忽略,因为\s*可以消耗尽可能多的内容,直到找到一个空字符。要验证这一点,请注意如果更改\s*的位置,您将获得不同的结果,这意味着仅消除\s*之前的表达式。
我认为你实际想要的正则表达式是:
:%s/\voutput|reg|\s+|\[.*\]|,//g

为了指示您想要替换至少有一个空格的位置。这对我来说效果很好。

1

你的正则表达式无法正常工作的原因。

看起来vim按照从左到右的顺序读取正则表达式,并尝试按顺序匹配联合的每个部分。

因此,在output|reg|\s*|\[.*\]|,中,\[.*\]永远不会被匹配,因为空字符串与在每个字符之间的\s*匹配。由于vim正则表达式引擎已经匹配到了某些内容,它立即执行替换操作。

如果您只是重新排列\s*的联合,则正则表达式可以正常工作。

所以命令应该是:%s/\voutput|reg|\[.*\]|,|\s*//g


0

这个有效(在末尾查找4个字母):

%s/^.*\<\(\a\{4}\),\s*$/\1/g

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接