在Vim中,如何在子表达式中进行替换?

In Vim, How to substitute within a subexpression?

我想在我所有的 class 名称前加上 o-,而不必手动调整每个 class 名称。我用 Vim.

我知道替代品可以完成这项工作,所以我想到了这个,这显然不起作用(也是我在这里的原因)。

:%s/class="[^"]*"/\='class="'.substitute(submatch(0), '[^o-]*', 'o-'.submatch(1), 'g').'"'/g

解释:

  1. class="[^"] - 匹配 class="foo bar baz"
  2. 的所有实例
  3. \='class="'.substitute(subexp).'"' - 替换找到的实例 class="subexp"
  4. subexp 中的每个 space 应该用原来的 class 前缀替换 class class o-

总而言之,在程序方面,对于每个 class="foo bar baz",将每个 class 名称替换为带有 o- 前缀的 class 名称。

提前致谢。

(奖金)编辑:如何编写以忽略或处理 class 已经以 o- 开头的名称,当遇到时,所以o-o- 而不是 编辑结果。

一种方法是利用 \zs...\ze,并且 submatch(0) 解析为 \zs...\ze:

之间匹配的字符串
:%s/\mclass="\zs.\{-}\ze"/\=substitute(submatch(0), '\<', 'o-', 'g')/g

如果您不想依赖它,您仍然可以使用显式分组:

:%s/\mclass="\zs\([^"]*\)\ze"/\=substitute(submatch(1), '\<', 'o-', 'g')/g

举个例子

class="foo bar baz"

这一行有效:

%s/class="\zs[^"]*\ze"/\=join( map(split(submatch(0)),"'o-'.v:val"), ' ')/

所以有嵌套的函数调用:

  • 我没有使用 \< 边界,因为如果你的 class 名称中有一些 "special" 字符,它将失败。例如。 # - or @。不知道你们的语言是不是这样。
  • submatch(0) 是 "foo bar baz"
  • split() 使其(每个 class)进入列表
  • map()o- 添加到每个 classname
  • join() 将修改后的列表转回字符串

所以执行这条命令后,你应该看到:

class="o-foo o-bar o-baz"

编辑 "Bonus" 要求:

我们只需要检查每个元素(class名称)。检查下面的代码,它应该适合你:

%s/class="\zs[^"]*/\=join(map(split(submatch(0)),"(v:val=~'^o-'?'':'o-').v:val"))/

这里我们有:

(v:val=~'^o-'?'':'o-').v:val

如果元素以 o- 开头,那么我们不再添加另一个 o-