0

我想在 Vim 中找到一种好方法来进行此搜索并替换以下内容 -

name_1
end
name_2
end

name_3
end

我在哪里取 name_"x" 并将其附加到它后面的“end”语句中。所以它看起来像这样 -

name_1
end_name_1
name_2
end_name_2
name_3

end_name_3

注意 - name_3 之前的空行破坏了“name_x”和“end”之间的恒定行距。所以我在想类似的东西

:g/\(name_x\)/,/end/ s/end/end_\1/

现在尝试像那样存储第一个模式是行不通的,但希望你明白这一点。这里有什么技巧吗?

谢谢

4

1 回答 1

3

您遇到的问题是\1指当前替换的匹配组而不是:g命令的模式。遗憾的是,您无法从以前的搜索中访问以前的匹配组。但是,有一些方法可以实现您的目标。我建议的第一个是宏。

首先从不匹配的行开始。这可以通过在需要时在文件顶部插入一个空行来完成(之后只需将其删除)。

  1. 开始宏搜索您的模式:/name_\d\+
  2. 猛拉直到你的模式结束:y//e
  3. 找到结束模式:/end/e
  4. 插入下划线a_
  5. 粘贴p
  6. 结束你的宏q
  7. 执行大量的宏。例如999@q

这是我使用的宏:

:let @q = "/name_\\d\\+\<cr>y//e\<cr>/end/e\<cr>a_\<esc>p"

另一种方法是以:global与您的尝试类似的方式使用该命令。

:g/name_\d\+/let @@=matchstr(getline('.'),'name_\d\+')|/end/s//\=submatch(0).'_'.@@/

我个人这太复杂了,但是有选择是很好的。该命令可以分解为以下部分:

  • :g/name_\d\+在匹配 name_ 和某个数字的每一行上执行一个命令
  • getline('.')将返回当前行的字符串
  • matchstr(getline('.'), 'name_\d\+')将只返回当前行的匹配部分
  • let @@ = matchstr(...)将匹配部分设置为默认寄存器
  • /end/s/:s将在匹配的以下行上执行 aend
  • s//\=.../匹配最后使用的模式并用 express 替换它。
  • submatch(0).'_'.@@创建一个包含整个匹配模式的字符串,后跟一个下划线和未命名寄存器的内容。

有关以下主题的更多信息,请参阅:

:h q
:h search-offset
:h :g
:h :let-@
:h registers
:h matchstr(
:h getline(
:h range
:h submatch(
于 2012-11-09T00:32:19.923 回答