如何在 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顶行,所以你实际上应该减去1
从 line()
返回的值):
%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
它会将 0
s 变成来自 1
的序列
ctrl-v
: 列模式
G
: select 第一列到最后一行。
g+ctrl-a
: 添加
或者您可以使用 awk
、column
和 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\+'/
我有一个文件,内容如下:
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顶行,所以你实际上应该减去1
从 line()
返回的值):
%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
它会将 0
s 变成来自 1
ctrl-v
: 列模式G
: select 第一列到最后一行。g+ctrl-a
: 添加
或者您可以使用 awk
、column
和 Vim 的过滤器命令。
:%!gawk 'NR>1 {=++i} 1' | column -t
解释:
:%!{cmd}
将 "filter" 范围,%
(整个文件),通过命令{cmd}
gawk '..'
将 运行 一个 awk one-linerNR>1 {..}
将 运行 一个 "block" 记录数大于 1(跳过 header)=++i
会将第一个字段设置为变量i
(pre-incremented)1
缺少{print}
将打印出行{cmd1} | {cmd2}
将命令{cmd1}
的输出通过管道传输到命令{cmd2}
的输入
column -t
将漂亮地打印表格形式的数据
我的 PatternsOnText plugin 有一个 :Renumber
命令(除此之外);它使用 :substitute
和 替换表达式 :
:%Renumber/^x'\d\+'/