Vim :s 替换一行中出现的特定 N < g 次

Vim :s replace specific N < g occurrences on a line

我正在尝试使用逗号 (,) 来分隔前两个数字字段中的千位 vim command

%s/\([0-9]\)\([0-9]\)\([0-9]\)\([0-9]\);/,;/g

但在这种情况下,它还会在第二行的 9,995 中添加逗号,我可以用什么来替换特定的 N < g 出现。

输入

BitstreamCyberCJK;Freeware;30275;28686;v2.0 ;beta (1998-03-17)
Y.OzFontN;Freeware;21957;7621;v13.00 sfnt rev 9995; Pen-Ji (2010-08-24)

预期输出

 BitstreamCyberCJK;Freeware;30,275;28,686;v2.0 ;beta (1998-03-17)
 Y.OzFontN;Freeware;21,957;7,621;v13.00 sfnt rev 9995; Pen-Ji (2010-08-24)

有一种方法可以重复最后一个命令:@: 另外,您可以指定重复次数,例如:10@:.

因此,从仅替换第一个匹配项开始:%s/\([0-9]\)\([0-9]\)\([0-9]\)\([0-9]\);/,;/

然后,因为我们已经完成了N个替换之一,所以重复N-1次。

例如,要替换前 10 个数字,请使用:

%s/\([0-9]\)\([0-9]\)\([0-9]\)\([0-9]\);/,;/
9@:

我会使用更短且更易于管理的搜索模式:

:%s/\(\d\)\(\d\{3}\);/,;/g

然后,我将删除 /g 标志以仅替换每行中的第一个匹配项,因为目标具体是 而不是 替换所有行中的所有匹配项:

:%s/\(\d\)\(\d\{3}\);/,;

然后,我会在每一行重复最后一个替换:

g&

参见 :help \d:help \{:help :s_flags:help g&

首先,我建议您清理正则表达式:

:%s/\([0-9]\)\([0-9]\{3}\);/,;/g

其次,最后的 g 标志使 vim 替换所有出现的地方。没有标志,它只会替换第一个。由于 % 运行 是每行的替换,%s//g 将替换每行中的第一个匹配项。

由于您想要替换前两次出现的位置,您只需 运行 替换两次即可。然而,我们想要在这里优雅一点。有 :& 命令重复最后一次替换。我们甚至可以将它们链接在一起:

:%s/\([0-9]\)\([0-9]\{3}\);/,;/ | norm %&

更新: 其他解决方案也可以这样使用:

:%s/\([0-9]\)\([0-9]\{3}\);/,;/ | norm g&

:%s/\([0-9]\)\([0-9]\{3}\);/,;/ | norm :@

上面已经有很好的答案,但我将分享我将如何处理它。 (因为我不想数“N”有多少,我不想重复替换却发现我做了太多,等等)

我会使用上面列出的替换项之一,例如 :%s/\(\d\)\(\d\{3}\);/,;/g。然后我 运行 进行第二次替换,搜索“rev”并删除逗号(如果存在):

%s/\(rev \d\),\(\d\{3\};\)//g
%                               g  all lines, and all occurences on a line
 s/                       /    /   substitute
   \(      \) \(        \)         backref capture groups
     rev \d                        text "rev " and a digit (backref 1)
             ,                     comma
                \d\{3\};           three digits and a semicolon (backref 2)
                               backrefs 1 and 2

一些注意事项--

  • 如果您知道“rev”在一行中只出现一次,那么您可以省略替换末尾的 g
  • 如果“rev”以某种方式出现在其他 文件中的上下文——可能是像“Foo bar abbrev 4,321”这样的文本—— 那么你要考虑到这一点。
  • 如果没有“rev”后跟数字和逗号的匹配项,则 Vim 将给出“未找到模式”消息。

此外,这将搜索带逗号的四位数。如果你想删除逗号的五位或六位数字的机会,那么你会使用这个,这几乎是一样的:

%s/\(rev \d\{1,3\}\),\(\d\{3\}\);//g
         \d\{1,3\}  ,                     1 to 3 digits followed by a comma