Vim正则表达式:删除数字除最后两位以外的所有内容

8

我有一个文件中包含以下文本

23456789

当我尝试使用命令替换上述文本时,
1,$s/\(\d\)\(\d\d\d\)\(\d\d\)*\>/\3\g

我得到了 89。应该是 6789 吗?有人能告诉我为什么是 89 吗。


12
请注意,如果您使用\v开关,可以避免所有这些反斜杠括号。1,$s/\v(\d)(\d\d\d)(\d\d)*>/\3/g更容易阅读。 - Brian Carper
1
你是否在寻找类似这样的内容: 1,$s/\v^\d{4}((\d{2})*)/\1/ - AmirW
5个回答

4

按照你的正则表达式,它会匹配一个数字,然后是三个数字,接着是任意数量的每组两个数字。因此,如果第三个匹配存在,它将始终是两个数字。在你特定的测试用例中,“89”在\4而不是\3。

将正则表达式更改为

 1,$s/\(\d\)\(\d\d\d\)\(\d\d\+\)\>/\3\g

由于第三组会捕获两个或更多数字(最多可以是所有数字),因此结果将为“6789”。


(\d\d)* 匹配2或多个2。在我们的情况下,它应该匹配最后4位数字。所以,\3不应该包含所有4个数字。 \4将什么都没有,因为我只有3个()。 - chappar
5
(\d\d)* 可以匹配长度为偶数的数字(如12,3456),但不能匹配长度不是偶数的数字(如789)。但是由于同一括号(即同一捕获组)用于多个数字对,因此它只会“捕获”最后一个数字。如果要确保仅匹配偶数倍长度的数字,请使用Hasturken的正则表达式。 - rampion

4
你需要在这里使用一个非捕获组,如下所示。
1,$s/\(\d\)\(\d\d\d\)\(\%(\d\d\)*\)\>/\3/g

这里的结果是6789,如果输入改变为...
2345678

将该行更改为278

2
我实际上正在寻找vim正则表达式中的非捕获组。 - lambacck

1

第三组被定义为2位数字长度。如果您想匹配最后4位数字,则需要使用\(\d\d\d\d\),末尾不带*。如果您只想匹配除前4位以外的所有数字,请将*放在组匹配内部而不是外部。


难道在第3组匹配时,不应该是最后2、4、6位数字吗? - chappar

0

我在nvi中尝试了这个命令,但它不起作用。在vim中它可以工作,只是你必须更正g前的最后一个倒置短横线为短横线,像这样:

1,$s/\(\d\)\(\d\d\d\)\(\d\d\)*\>/\3/g

然后它会被替换成89。 原因是你使用*表示最后的\d\d可以重复零次、一次或多次,并且使用>表示结束单词边界。 使用第三组,你要求最后一组,但由于*,最后两个数字(\d\d)是89。 去掉*>,你可以得到6789。像这样:

1,$s/\(\d\)\(\d\d\d\)\(\d\d\)/\3/g

注意 > 符号,它在这里扮演了一个棘手的角色,因为使用以下命令:1,$s/\(\d\)\(\d\d\d\)\(\d\d\)\>/\3,你会得到 2389 的结果!因为从单词边界的角度来看,dddddd 匹配的是 456789,并被最后两个 dd 替换,即 89。所以你得到了 23+89,让人惊叹!LOL


0

你可能需要(需要额外的包装组):

%s/\(\d\)\(\d\d\d\)\(\(\d\d\)*\)\>/\3\g

虽然我不确定你为什么要捕获前两个组。


为什么我需要在第三组加上额外的括号?我的原始示例有什么问题? - chappar
"(\d\d)"确实可以匹配任何数字对,但它不会为您捕获它们以便稍后使用。要捕获它,您需要将其包装在自己的组中-也就是额外的一组括号。 - orip

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