匹配模式,然后使用模式替换

时间:2012-11-08 23:03:14

标签: vim

我想在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/

现在尝试存储第一个模式并不起作用,但希望你能得到这个想法。这里有什么技巧吗?

由于

1 个答案:

答案 0 :(得分:3)

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

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

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

    :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匹配的以下行执行end
    • s//\=.../与上次使用的模式匹配,并将其替换为快速。
    • submatch(0).'_'.@@创建一个字符串,其中包含整个匹配的模式,后跟下划线和未命名寄存器的内容。

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

    :h q
    :h search-offset
    :h :g
    :h :let-@
    :h registers
    :h matchstr(
    :h getline(
    :h range
    :h submatch(