【问题标题】:vim: substitute specific character, but only after nth occurancevim:替换特定字符,但仅在第 n 次出现之后
【发布时间】:2017-03-15 00:30:47
【问题描述】:

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

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

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

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

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

问题:用“;”替换所有选项卡,除了最后一个字段,俱乐部需要用“,”分隔。

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

第一部分很简单::2,$s/\t/,/g 但第二部分,我似乎无法弄清楚。

任何帮助将不胜感激。

谢谢,芝诺

【问题讨论】:

  • 它必须是正则表达式解决方案,还是使用其他 vim 功能(全局命令、普通命令、宏等)的某种组合可以?
  • 是的,命令是允许的,我只是“假设”它会用正则表达式完成,我会相应地更改标题

标签: regex vim vi text-manipulation


【解决方案1】:

这个答案类似于@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))。然后我们用替换表达式的结果 (\=substitute(...)) 替换整个匹配 (submatch(0))。相比之下,替换表达式很简单,因为它只是将所有制表符转换为分号。

最后一个替换只是将行中的任何其他选项卡更改为逗号。

:help sub-replace-expression

【讨论】:

  • 这似乎可行!只有一个问题:点后面应该有一个星号,我说得对吗?
  • 没有。 * 将是一个贪婪的匹配,并且会吃掉所有东西,直到最后一个标签。 {-} 是非贪婪版本。在这种情况下,由于{7},这并不重要,但总的来说,我发现最好使用非贪婪匹配,除非你真的想要贪婪。
  • 哦,好的,谢谢!会接受这个答案而不是我的答案,因为我认为它比我的解决方案更好。
【解决方案2】:

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

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

解释:

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

:2,$norm 7@q

这与在指定范围内的每一行上直接输入7@q(例如“运行宏'q'七次”)基本相同。从那里,我们可以简单地用逗号替换每个选项卡。

:2,$s/\t/,/g

【讨论】:

  • 另外,您知道,还有一个dedicated vim site,您可以在以后发布您的问题。
  • 似乎是一个可靠的响应,我将立即对其进行测试。 '\' 是做什么用的?
  • "\&lt;cr&gt;" 是您描述文字回车的方式。以这种方式输入它很重要,以便实际运行替代命令。否则,你最终会得到类似s/\t/;:s/\t/;:s/\t/;:s/\t/;:s/\t/;:s/\t/;:s/\t/; 和 vim 等你回车的东西。
  • 好的,我运行了命令,一切似乎都是正确的,除了一件事:从第 2 行开始(应该替换选项卡),只有第一个选项卡被分号替换。在第 3 行,有 2 个分号,依此类推。当到达第 8 行时,分号的数量刚好合适 (7),再往前,分号的数量保持在 7。这是怎么回事?
  • @zenodhaene 0_0 我真的不知道。它对我来说非常好。也许你输入错误?我唯一能想到的另一件事就是上传文件,这样我就可以试试看。
【解决方案3】:
:2,$s/\t\(.*\t\)\@=/;/g
:2,$s/\t/,
  • 将以后有选项卡的任何选项卡更改为;
  • 将所有剩余的选项卡更改为,

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

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

【讨论】:

  • 当我看到您的回答时,最后一个选项卡被逗号替换。然而,并不是每一行都是一样的,所以一个球员可以有一个球杆:那么它不需要逗号,或者一个球员可以有 3 个球杆,然后它需要两个逗号
【解决方案4】:

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

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

【讨论】:

  • 是的,我见过你(或其他人)的插件,但我宁愿不用插件来完成它,因为解决方案应该可以由老师重现。虽然我找到了答案,但我会自己回答。感谢您的回答!
【解决方案5】:

我们通过手动捕获前 8 个组 ([^\t]*\t)(...)(...) 解决了这个问题,然后用分号分隔它们 (\1;\2;...;) 然后用逗号替换剩余的标签 | 2,$s/\t/,/g

感谢所有努力提供帮助的人!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 2018-03-24
    • 2011-08-25
    相关资源
    最近更新 更多