关于linux:如何使用子匹配值在Vim中搜索和替换

How to search and replace in Vim with submatch values

我的HTML看起来像这样

1
2
3
4
5
<form>
  <input id="firstname" value=""/>
  <input id="lastname" value=""/>
  <input id="email" value=""/>
</form>

我想在每个输入字段中添加name ="{id-name}"(参见下面的示例代码)

1
2
3
4
5
<form>
  <input id="firstname" name="firstname" value=""/>
  <input id="lastname" name="lastname" value=""/>
  <input id="email" name="email" value=""/>
</form>

我怎么能用Vim做到这一点?

我在尝试

1
%s/id=".*"/\=submatch(0)/g

这导致了两个问题:

1)搜索,从第一个报价搜索到最后一个报价。 它应该从第一个引号搜索到下一个引用。

enter image description here

2.)submatch(0)正在获取搜索的全部结果。 我怎样才能将它隔离到id="{value}"之间的值?

我经常遇到这个问题,弄清楚这个vim命令可以帮助我节省很多时间。 主要是将搜索结果拆分为submatch()我还看到堆栈上的人使用\1 \2而不是submatch()来存储结果,这种方法更好吗?

任何帮助将不胜感激! 谢谢!


我的第一个想法是这个问题在Vim Stack Exchange上更合适......

但无论如何我会在这里回答

您遇到的第一个问题称为贪婪。基本的想法是*量化是贪婪的,所以它试图匹配尽可能多的文本。可以在此处找到更深入的解释。

要解决这个问题,你可以简单地使用非贪婪的*,即\{-}。由于这不是贪婪的,它会尝试尽可能少地匹配文本。例如,看看这个文字:

1
"hello","world","test"

运行

1
:s/".*"

会删除所有东西,但是

1
:s/".\{-}"

只会删除"hello"

要解决第二个问题,您需要研究捕获组。基本上,括号中的任何内容都将被放入第1组,然后下一对括号将是第2组,依此类推。默认情况下,整个匹配的模式放在组0中。

我还建议不要使用eval运算符,即\=。这使事情变得不必要地冗长。你的例子完全等同于

1
:%s/id=".*"/\0/g

由于\0表示组0,\1表示组1等。

所以你可以这样做:

1
:%s/id="\(.\{-}\)"/\0 name="\1"/g

现在,还有一些小技巧:

  • 您可以使用&代替\0

  • 使用\v打开魔法,这样你就可以删除一些反斜杠(参见:help /\v)

  • 由于您只想每行替换一个匹配项,因此不需要将/g放在最后。

  • 把这一切放在一起,我会推荐以下正则表达式:

    1
    :%s/\vid=(.{-})/& name="\1"