gVim用计数器查找/替换

Mer*_*ham 15 regex vim counter replace

有没有办法在gVim搜索/替换中插入某种计数器变量的值?

例如转换这个文件:

<SomeElement Id="F" ... />
<SomeElement Id="F" ... />
<SomeElement Id="F" ... />
Run Code Online (Sandbox Code Playgroud)

到这个结果文件:

<SomeElement Id="1" ... />
<SomeElement Id="2" ... />
<SomeElement Id="3" ... />
Run Code Online (Sandbox Code Playgroud)

我想这个命令看起来像:

:%s/^\(\s*<SomeElement Id="\)F\(".*\)$/\1<insert-counter-here>\2/g
Run Code Online (Sandbox Code Playgroud)

我正在使用他们提供的安装程序中最新的Windows版本.我强烈不想安装任何其他工具.

另外,我最好避免安装脚本来支持这一点,但我愿意,如果这是唯一的方法.

ib.*_*ib. 18

使用表达式特征替换可以使用可增加的计数器(请参阅参考资料:help sub-replace-\=).由于\=构造仅允许表达式,:let因此禁止使用该命令,因此无法以通常的方式设置变量.但是,如果该变量是列表或字典,则有一个简单的技巧可以更改表达式中变量的值.在这种情况下,其内容可以由map()函数修改.以这种方式,对问题中描述的情况的替换将如下所示.1

:let n=[0] | %s/Id="F"/\='Id="'.map(n,'v:val+1')[0].'"'/g
Run Code Online (Sandbox Code Playgroud)

或者更好,2

:let n=[0] | %s/Id="\zsF\ze"/\=map(n,'v:val+1')/g
Run Code Online (Sandbox Code Playgroud)

这个简短的单线程完全解决了这个问题.

对于诸如上述的频繁更换,可以定义辅助功能

function! Inc(x)
    let a:x[0] += 1
    return a:x[0]
endfunction
Run Code Online (Sandbox Code Playgroud)

并使替换命令更短,

:%s/Id="\zsF\ze"/\=Inc(n)/g
Run Code Online (Sandbox Code Playgroud)

1 这里棘手的部分是替换的替代部分.因为它从\=其余部分开始被解释为Vim的表达式.因此,'Id="'.map(n, 'v:val+1').'"'是一个普通的表达.这里'Id="'使用. 函数调用的返回值map(n, 'v:val+1')和另一个字符串连接字符串文字(使用运算符)'"'.函数map需要两个参数:一个列表(如本例所示)或一个字典,以及一个包含表达式的字符串,该表达式应该针对给定列表或字典中的每个项进行评估.特殊变量v:val表示单个列表项.因此,'v:val+1'字符串将被评估为增加1的列表项.

2\zs\ze图案原子用于设置开始和图案的端部,以取代,分别为(见:help /\zs:help /\ze).这样,替换命令的整个搜索部分匹配,但只有部分\zs\ze替换部分.这避免了替代表达式中的笨拙连接.

  • @ib:哇,这个问题已经发现了丰富的信息.在我的很多搜索中,`\ zb`和`\ ze`将摆脱大量的零宽度断言开销.我希望我可以作为小费回复赏金;) (3认同)

anu*_*ava 12

嗯,这有点棘手.这是我到目前为止所得到的.在vim会话中尝试这两个map命令:

:nmap %% :let X=1<cr>1G!!
:nmap !! /^\s*<SomeElement Id="F"<cr>:s/F"/\=X.'"'/<cr>:let X=X+1<cr>!!
Run Code Online (Sandbox Code Playgroud)

一旦那是按下%%开始有趣的部分:)

它使您的给定文件为:

<SomeElement Id="1" ... />
<SomeElement Id="2" ... />
<SomeElement Id="3" ... />
<SomeElement Id="4" ... />
Run Code Online (Sandbox Code Playgroud)

说明:

第一个 nmap命令将以下序列映射到击键%%:

  • 将变量X初始化为1
  • 移动到第一个文件的开头
  • 调用另一个映射的击键 !!

第二个 nmap命令将以下序列映射到击键!!:

  • 搜索下一个模式 ^\s*<SomeElement Id="F"
  • 如果找到上面的模式,则搜索并替换F"变量X和引号"
  • 将vim变量X递增1
  • 通过调用来递归调用自身 !!
  • 单点.用于在vim中串联字符串,非常类似于php

^\s*<SomeElement Id="F"文件中不再找到模式时,此递归调用将停止.


jma*_*eli 8

Vim wiki说明似乎是最简单的解决方案(至少对我而言).

下面的实施例的替换所有出现PATTERNREPLACE_[counter](REPLACE_1,REPLACE_2等等):

:let i=1 | g/PATTERN/s//\='REPLACE_'.i/ | let i=i+1
Run Code Online (Sandbox Code Playgroud)

要回答这个问题,它可能如下所示:

:let i=1 | g/SomeElement Id="F"/s//\='SomeElement Id="'.i.'"'/ | let i=i+1
Run Code Online (Sandbox Code Playgroud)


小智 6

很简单的解决方案 我不得不这样做几次.

:let i=1 | g/^\(\s*<SomeElement Id="\)F\(".*\)$/s//\=submatch(1).i.submatch(2)/ | let i=i+1
Run Code Online (Sandbox Code Playgroud)

基于以下提示.http://gdwarner.blogspot.com/2009/01/vim-search-and-replace-with-increment.html