首页 > 解决方案 > vim - 用逗号分割行并为每个标记添加前缀

问题描述

我有这样的行:

<prefix> <token1>, <token2>, .... <tokenN>;

其中令牌的数量是可变的,每个令牌是一个字符或数字。

我想像这样在 Vim 中拆分它们:

<prefix> <token1>;
<prefix> <token2>;
...
<prefix> <tokenN>;

我尝试抓住这样的模式,/<prefix>\s\+\(\w\+,\s*\)\{1,}\(\w\+\);/但我不确定如何提取可变数量的令牌(\1 和 \2 仅给定 tokenN-1 和 tokenN)。

想法?提前致谢。

标签: vim

解决方案


如果您的前缀在任何地方都是固定的(您建议使用以 开头的模式/<prefix>\s\+...),那么您可能可以使用如下简单的东西:

:g/^<prefix>\s/s/,\s\+/;\r<prefix> /g

换句话说,对于以 开头的每一行<prefix>,用分号、回车和<prefix>后跟空格的固定替换所有逗号(后面有空格)。


但是假设你<prefix>的更复杂和多变,并且你想在正则表达式中捕获它:

使用命令解决此问题的一种方法:substitute是使用对函数的进一步调用substitute()作为替换的一部分,您可以使用它来替换任意数量的逗号。

一种可能的方法是:

:s/\(\S\+\)\s\+[^,]*\zs\(,\s*[^,]*\)*\ze;$/\=substitute(submatch(0),',\s*',";\r".submatch(1)." ",'g')/

打破模式:

  • \(\S\+\):匹配捕获组中的前缀。(您可以使用更好、更具体的内容,而不仅仅是非空白,以仅正确匹配您关心的行。)
  • \s\+: 跳过空格。
  • [^,]*:跳过第一个令牌。
  • \zs: 标记比赛的开始。替换只会替换这部分。
  • \(,\s*[^,]*\)*:一个或多个标记的序列,前面有逗号和可选的空格。
  • \ze: 标记比赛的结束。
  • ;$: 匹配所有末尾的分号。

在这一点上,策略再次是用分号、回车和前缀替换逗号,但要动态地这样做。

这是通过在替换中使用这些来实现的:

  • \=:在替换中使用表达式(请参阅:help sub-replace-expression.)
  • substitute(submatch(0),',\s*',";\r".submatch(1)." ",'g'):用分号、回车和前缀的序列替换逗号(以及它们后面的可选空格),然后是空格。
  • submatch(0):我们正在比赛中执行这样的替换(部分在\zs和之间\ze。)
  • ";\r":替换的开头,分号和回车。
  • .: 点运算符连接 Vimscript 中的字符串。
  • submatch(1): 指回捕获组 1,我们在本例中使用它来捕获前缀。
  • 'g':替换所有匹配项。

这是一个相当复杂的替换,但具有在单个:s命令中处理替换的优点,这使得在一个范围内使用它或稍后重复它更容易,而无需记录宏。

在替换中使用该substitute()函数的技术:s对于处理捕获组不够用的情况也是一种有用的技术,例如您提供的那个。


推荐阅读