vim:替换特定字符,但仅在第 n 次出现后

vim: substitute specific character, but only after nth occurance

我需要在 vim 中做这个关于正则表达式和文本操作的练习。

所以我有这个关于历史上得分最多的足球运动员的文件,其中 50 个条目如下所示:

1 Cristiano Ronaldo Portugal 88 121 0.73 03 Manchester United Real Madrid

字段之间的空格是制表符 (\t)

每个字段响应不同的类别:等等... 最后一个字段包含玩家曾效力过的一个或多个俱乐部。(因此不是固定数量的俱乐部)

问题:将所有制表符替换为“;”,但最后一个字段除外,其中俱乐部需要用“,”分隔。

所以我想:我就把它们全部换成逗号,然后我把前7个逗号换成分号。但是,你是怎么做的?一切 - 从正则表达式到 vim 命令 - 都是允许的。

第一部分很简单::2,$s/\t/,/g 但是第二部分,我好像想不通了。

如有任何帮助,我们将不胜感激。

谢谢,芝诺

这是您可以做到的一种方法:

:let @q=":s/\t/;\<cr>"
:2,$norm 7@q
:2,$s/\t/,/g

解释:

首先,我们定义一个宏 'q',它将用分号替换 one 选项卡。现在,在任何一行上我们都可以简单地 运行 这个宏 n 次来替换第一个 n 选项卡。要自动对每一行执行此操作,我们使用 norm 命令:

:2,$norm 7@q

这与在指定范围内的每一行上字面键入 7@q(例如 "run macro 'q' seven times")本质上是一样的。从那里,我们可以简单地用逗号替换每个选项卡。

:2,$s/\t/,/g
:2,$s/\t\(.*\t\)\@=/;/g
:2,$s/\t/,
  • 将以后有标签的任何标签更改为;
  • 将所有剩余的标签更改为 ,

编辑:被误解了。这是固定版本:

:2,$s/\(\(\t.*\)\{7}\)\@<=\t/,/g
:2,$s/\t/;/g
  • 将前面有七个选项卡的任何选项卡更改为 ,
  • 将所有剩余的标签更改为 ;

我的 PatternsOnText plugin 有一个 :SubstituteSelected 命令,可以指定匹配位置。有了这个,您可以轻松地将前 8 个选项卡替换为分号,然后使用常规替换将其余选项卡更改为逗号:

:2,$SubstituteSelected/\t/;/g 1-8
:2,$s/\t/,/g

我们通过手动捕获前 8 个组 ([^\t]*\t)(...)(...) 然后用分号分隔它们 (;;...;) 然后用逗号 | 2,$s/\t/,/g [=13= 替换其余选项卡来解决问题]

感谢大家的帮助!

这个答案类似于@Amadan 的答案,但它利用提供表达式作为替换字符串的能力来实际完成将第一组制表符更改为分号的困难部分:

%s/\v(.{-}\t){7}/\=substitute(submatch('0'), '\t', ';', 'g')/|%s/\t/,/g

分解为一组三个替代命令。前两个用 sub-replace-expression:

拼凑而成
%s/\v(.{-}\t){7}/\=substitute(submatch('0'), '\t', ';', 'g')/

它所做的是以非贪婪的方式找到任何字符后跟一个制表符的七次出现({7})。 ((.{-}\t))。然后我们将整个匹配项 (submatch(0)) 替换为替换表达式 (\=substitute(...)) 的结果。相比之下,替换表达式很简单,因为它只是将所有制表符转换为分号。

最后一个替换只是将行中的任何其他制表符更改为逗号。

:help sub-replace-expression