【问题标题】:How to use regex in vim to replace with an incrementing number variable如何在vim中使用正则表达式替换为递增的数字变量
【发布时间】:2020-01-05 11:09:33
【问题描述】:

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

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 替换为增量变量?

【问题讨论】:

标签: regex vim vi


【解决方案1】:

一次性

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

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

如果最后一个 1 不在第 1 行,则将其替换为标题(id、电话、姓名)行的行号。

两步

您只需将代码中的1 替换为0 即可获得关注

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

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

ctrl-vGgctrl-a

它将0s 转换为来自1 的序列

  • ctrl-v:列模式
  • G :选择第一列直到最后一行。
  • g+ctrl-a:添加

【讨论】:

  • 很有趣
【解决方案2】:

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

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

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

它查找^x'\d\+' 模式的所有出现(每行一个),并将其替换为i 的值,该值在每次找到匹配项时递增。与 noted in comments 一样,|g 替换“代码”的一部分,如 "| is used to execute more than one command at a time"

另一种解决方案是使用line() 命令(考虑到您的文件有一个标题顶行,因此您实际上应该从line() 返回的值中减去1):

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

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

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

Using an expression in substitute command 页面上还有其他有趣的“正则表达式中的增量”示例:

  • 为文件中的所有行编号(插入行号,后跟一个制表符):
    :%s/^/\=line('.')."\t"/
  • 为一系列行编号(从第 10 行到第 20 行):
    :10,20s/^/\=line('.')."\t"/
  • 从 1 开始依次编号一系列行:
    :let counter=0|10,20g//let counter=counter+1|s/^/\=counter."\t"
    
  • 从 1 开始为范围内的所有段落编号(假设段落由一个或多个空行分隔):
    :let counter=0|1,20g/^$\n^\s*[^\s]/let counter=counter+1|+1s/^/\=counter."\t"
    注意:如果文件的第一段上面没有空行,上述命令将不起作用。

【讨论】:

  • 这是一个非常好的答案。但它真正有趣的部分是| let i=i+1g// 命令的一部分,因此对每一行都执行。乍一看,它看起来不像那样。解释那部分会改善这个答案。
  • 哦,谢谢您的指导和建议
【解决方案3】:

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

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

解释:

  • :%!{cmd} 将“过滤”范围,%(整个文件),通过命令 {cmd}
  • gawk '..' 将运行 awk 单行代码
  • NR>1 {..} 将为大于 1 的记录号运行一个“块”(跳过标题)
  • $1=++i 会将第一个字段设置为变量 i(预递增)
  • 1 缺少 {print} 将打印出该行
  • {cmd1} | {cmd2} 将命令{cmd1} 的输出通过管道传输到命令{cmd2} 的输入
  • column -t 将漂亮地打印表格数据

【讨论】:

    【解决方案4】:

    我的PatternsOnText plugin 有(以及其他许多):Renumber 命令;它使用 :substitute替换表达式 简化了典型解决方案:

    :%Renumber/^x'\d\+'/
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-09
      • 2015-11-03
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多