Vim正则表达式反向引用

68

我想要做这件事:

%s/shop_(*)/shop_\1 wp_\1/

为什么 shop_(*) 没有匹配到任何内容?


我离成功又近了一步:%s/shop_/& wp_\1 - nnyby
1
如果我理解不正确,请尝试添加示例。 - Stephen
7
如果在正则表达式的使用示例中附加一个实例,这个问题将更有用于未来的 Stack Overflow 用户。 - LondonRob
4个回答

81
这里有几个问题。
  1. 在vim正则表达式中,括号不是用来捕获的 -- 你需要使用 \( \) 来捕获。

  2. * 不是你想象中的意思。它的意思是“前面的字符出现0次或多次”,因此你的正则表达式的意思是“一个包含 shop_ 后跟0个或多个 ( 和一个字面量 ) 的字符串”。
    你要找的是 .,在正则表达式中它表示“任何字符”。与星号一起组合成 .* 表示“0个或多个任何字符”。你可能想至少匹配一个字符,所以使用 .\++ 表示“前面的字符出现1次或多次”)

使用这个: %s/shop_\(.\+\)/shop_\1 wp_\1/

最后一个斜杠后面可以选择加上 g ,这样就会替换一行中的所有实例而不仅仅是第一个实例。


只是一个小问题:现有的正则表达式没有搜索字面上的 *),而只是字面上的 ) - Stephen
基本上,Vim希望进行反向转义:转义所有正则表达式语法(例如\(re\)\?move以匹配'move'和'remove'),而不是转义任何应该按字面意义理解的内容。 - Luc

33

如果我理解正确,您想要的是%s/shop_\(.*\)/shop_\1 wp_\1/

转义捕获括号并使用.*匹配任意数量的任何字符。

(您的搜索正在查找以“ shop_”开头的任意数量的左圆括号后跟一个右圆括号)


3

如果你想避免不得不转义捕获括号,并使正则表达式模式语法更接近其他实现(例如PCRE),请在模式开头添加\v(非常神奇!)(有关更多信息,请参见:help\magic):

:%s/\vshop_(*)/shop_\1 wp_\1/

0

如果你看这里:regex-info,@Luc,你会发现vim的行为是正确的。这里有一个来自sed的并行例子:

echo "123abc456" | sed 's#^([0-9]*)([abc]*)([456]*)#\3\2\1#'
sed: -e expression #1, char 35: invalid reference \3 on 's' command's RHS

而使用“转义”括号,则可以正常工作:

echo "123abc456" | sed 's#^\([0-9]*\)\([abc]*\)\([456]*\)#\3\2\1#'
456abc123

我不喜欢看到Vim被诋毁 - 特别是当它表现正确时。

PS 我试图将其添加为评论,但无法正确格式化。


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