如何在 vim 中使用正则表达式替换为递增的数字变量

How to use regex in vim to replace with an incrementing number variable

我有一个文件,内容如下:

id      phone   name
x'1234' 12345   jack
x'4567' 45678   Jojo
x'7890'  89456  Dio
x'4591'  34872  joseph

我想把它解析成这样:

id  phone   name
1   12345   jack
2   45678   Jojo
3    89456  Dio
4    34872  joseph

我知道基本正则表达式可以将所有 id 替换为任何字符串 像这样:

:%s/x'\(\w\+\)'/1/g

它将变成:

id  phone   name
1   12345   jack
1   45678   Jojo
1    89456  Dio
1    34872  joseph

如何将 id 替换为增量变量?

请注意,您可以在替换命令 (:s) 中使用表达式作为替换字符串。当替换字符串以 \= 开头时,它被评估为表达式。

这里,一个可能的解决方案

:let i=1 | g/^x'\d\+'/s//\=i/ | let i=i+1

它会找到 ^x'\d\+' 模式的所有出现(每行一次),并用每次找到匹配项时递增的值 if i 替换它。正如 noted in comments, the | is a part of the g replacing "code", as "| is used to execute more than one command at a time".

另一个解决方案是使用line()命令(考虑到你的文件有一个header顶行,所以你实际上应该减去1line() 返回的值):

%s/^x'\d\+'/\=line('.')-1/

^x'\d\+' 正则表达式 匹配

  • ^ - 行首
  • x' - x' 字符串
  • \d\+ - 1+ 位数
  • ' - 一个 ' 字符。

Using an expression in substitute command 页面上还有其他有趣的 "increment number in regex" 示例:

  • Number all the lines in a file (insert line number followed by a tab):
    :%s/^/\=line('.')."\t"/
  • Number a range of lines (from line 10 to line 20):
    :10,20s/^/\=line('.')."\t"/
  • Number a range of lines sequentially starting from 1:
    :let counter=0|10,20g//let counter=counter+1|s/^/\=counter."\t"
  • Number all the paragraphs in range starting from 1 (assuming the paragraphs are separated by one or more blank lines):
    :let counter=0|1,20g/^$\n^\s*[^\s]/let counter=counter+1|+1s/^/\=counter."\t"
    Note: The above command does not work for the first paragraph in the file if there is no blank line above it.

one-shot

您可以像其他答案那样声明一个变量,或者:

:%s/^x'\([^']*\)'/\=line('.')-1/  

将最后一个 1 替换为您的 header (id, phone, name) 行的行号,如果它不在第 1 行。

两步

您只需将代码中的 1 替换为 0 即可获得以下内容

id  phone   name
0   12345   jack
0   45678   Jojo
0    89456  Dio
0    34872  joseph

然后你可以将光标移动到第一个id 0,然后按:

ctrl-v G g ctrl-a

它会将 0s 变成来自 1

的序列
  • ctrl-v: 列模式
  • G : select 第一列到最后一行。
  • g+ctrl-a: 添加

或者您可以使用 awkcolumn 和 Vim 的过滤器命令。

:%!gawk 'NR>1 {=++i} 1' | column -t

解释:

  • :%!{cmd} 将 "filter" 范围,%(整个文件),通过命令 {cmd}
  • gawk '..' 将 运行 一个 awk one-liner
  • NR>1 {..} 将 运行 一个 "block" 记录数大于 1(跳过 header)
  • =++i 会将第一个字段设置为变量 i (pre-incremented)
  • 1 缺少 {print} 将打印出行
  • {cmd1} | {cmd2} 将命令 {cmd1} 的输出通过管道传输到命令 {cmd2}
  • 的输入
  • column -t 将漂亮地打印表格形式的数据

我的 PatternsOnText plugin 有一个 :Renumber 命令(除此之外);它使用 :substitute 替换表达式 :

简化了典型的解决方案
:%Renumber/^x'\d\+'/