Vim:用列表中的数字替换每行选择的第一个单词
Vim: Replace first word on each line of selection with number in list
我有一个大文件,其中包含一个 selection 和乱码。它应该是 seqeunce 1, 2, 3, ... 但有几行搞砸了。我想改变类似
的东西
foo
bar
1 foobar
12345 foobar
6546458 foobar
4 foobar
到
foo
bar
1 foobar
2 foobar
3 foobar
4 foobar
我知道我可以使用 3,$
之类的东西来 select 我关心的行和 put = range(1,1000)
来创建以我想要的数字开头的新行,但我想把这些数字在当前有数据的行上,而不是新行。混乱的数字有几个字符长,但总是一个字。谢谢。
您可以使用以下功能:
function Replace()
let n = 1
for i in range(0, line('$'))
if match(getline(i), '\v^\d+\s') > -1
execute i . 's/\v^\d+/\=n/'
let n = n + 1
endif
endfor
endfunction
它遍历整个文件,检查每一行是否以一个数字开头,后跟一个 space 字符,并用随着每次更改而递增的计数器进行替换。
这样称呼它:
:call Replace()
在你的例子中产生:
foo
bar
1 foobar
2 foobar
3 foobar
4 foobar
/^\d\+\s -- Searches for the first occurrence
ciw0<Esc> -- Replaces the word under cursor with "0"
yiw -- Copies it
:g//norm viwp^Ayiw
-- For each line that matches the last search pattern,
-- Replace the current word with copied text,
-- Increment it,
-- Copy the new value.
(<Esc>
就是 Esc。^A
输入为 Ctrl+ V, Ctrl+A)
ciw
-- 改变内字。 (:help c
)
:g
-- 全局搜索。 (:help :g
)
viw
-- Select 内字。 (:help v
)
p
-- 粘贴(替换选择)(:help v_p
)
^A
-- 递增。 (:help CTRL-A
)
yiw
-- Yank 内部单词。 (:help y
)
执行以下操作:
:let i=1
:g/^\d\+/s//\=i/|let i=i+1
概览
设置一些变量 (let i=1
) 用作我们的计数器。在以数字 (:g/^\d\+/
) 开头的每一行上,我们执行替换 (:s//\=i/
) 以用我们的计数器 (\=i
) 替换模式,然后递增我们的计数器 (let i=i+1
).
为什么要使用 :g
?为什么不只是 :s
?
您可以只使用一个替换命令来完成此操作,但是子替换表达式 \=
需要一个表达式来求值(请参阅 :h sub-replace-expression
)。由于 let i = i + 1
是一个声明,因此它不会有用。
有几种方法可以解决这个问题:
- 创建一个函数来递增一个变量然后return它
- 改用数组,然后(就地)更改内部数字,然后 return 数组外的值。例如
map(arr, 'v:val+1')[0]
- 如果每行只有 1 个替换,则执行上面的
:g
技巧
使用就地数组修改的完整示例:
:let i=[1]
:%s/^\d\+/\=map(i,'v:val+1')[0]
就个人而言,我会使用您记得的任何方法。
更多帮助
:h :s
:h sub-replace-expression
:h :g
:h :let
:h expr
:h map(
:h v:val
我有一个大文件,其中包含一个 selection 和乱码。它应该是 seqeunce 1, 2, 3, ... 但有几行搞砸了。我想改变类似
的东西foo
bar
1 foobar
12345 foobar
6546458 foobar
4 foobar
到
foo
bar
1 foobar
2 foobar
3 foobar
4 foobar
我知道我可以使用 3,$
之类的东西来 select 我关心的行和 put = range(1,1000)
来创建以我想要的数字开头的新行,但我想把这些数字在当前有数据的行上,而不是新行。混乱的数字有几个字符长,但总是一个字。谢谢。
您可以使用以下功能:
function Replace()
let n = 1
for i in range(0, line('$'))
if match(getline(i), '\v^\d+\s') > -1
execute i . 's/\v^\d+/\=n/'
let n = n + 1
endif
endfor
endfunction
它遍历整个文件,检查每一行是否以一个数字开头,后跟一个 space 字符,并用随着每次更改而递增的计数器进行替换。
这样称呼它:
:call Replace()
在你的例子中产生:
foo
bar
1 foobar
2 foobar
3 foobar
4 foobar
/^\d\+\s -- Searches for the first occurrence
ciw0<Esc> -- Replaces the word under cursor with "0"
yiw -- Copies it
:g//norm viwp^Ayiw
-- For each line that matches the last search pattern,
-- Replace the current word with copied text,
-- Increment it,
-- Copy the new value.
(<Esc>
就是 Esc。^A
输入为 Ctrl+ V, Ctrl+A)
ciw
-- 改变内字。 (:help c
):g
-- 全局搜索。 (:help :g
)viw
-- Select 内字。 (:help v
)p
-- 粘贴(替换选择)(:help v_p
)^A
-- 递增。 (:help CTRL-A
)yiw
-- Yank 内部单词。 (:help y
)
执行以下操作:
:let i=1
:g/^\d\+/s//\=i/|let i=i+1
概览
设置一些变量 (let i=1
) 用作我们的计数器。在以数字 (:g/^\d\+/
) 开头的每一行上,我们执行替换 (:s//\=i/
) 以用我们的计数器 (\=i
) 替换模式,然后递增我们的计数器 (let i=i+1
).
为什么要使用 :g
?为什么不只是 :s
?
您可以只使用一个替换命令来完成此操作,但是子替换表达式 \=
需要一个表达式来求值(请参阅 :h sub-replace-expression
)。由于 let i = i + 1
是一个声明,因此它不会有用。
有几种方法可以解决这个问题:
- 创建一个函数来递增一个变量然后return它
- 改用数组,然后(就地)更改内部数字,然后 return 数组外的值。例如
map(arr, 'v:val+1')[0]
- 如果每行只有 1 个替换,则执行上面的
:g
技巧
使用就地数组修改的完整示例:
:let i=[1]
:%s/^\d\+/\=map(i,'v:val+1')[0]
就个人而言,我会使用您记得的任何方法。
更多帮助
:h :s
:h sub-replace-expression
:h :g
:h :let
:h expr
:h map(
:h v:val