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)

执行以下操作:

: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