gVim用计数器查找/替换

时间:2011-05-09 20:51:59

标签: regex vim counter replace

有没有办法在gVim search / replace中插入某种计数器变量的值?

e.g。转换此文件:

<SomeElement Id="F" ... />
<SomeElement Id="F" ... />
<SomeElement Id="F" ... />

到这个结果文件:

<SomeElement Id="1" ... />
<SomeElement Id="2" ... />
<SomeElement Id="3" ... />

我想这个命令看起来像是:

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

我使用的是最新的Windows版本,来自他们提供的安装程序。我强烈不想安装任何其他工具。

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

6 个答案:

答案 0 :(得分:18)

可以使用替换来增加一个计数器 表达特征(见:help sub-replace-\=)。自\=构造以来 只允许表达式,禁止使用:let命令,和 因此,变量无法按常规方式设置。但是,有 一个简单的技巧来改变表达式中变量的值 变量是列表或字典。在这种情况下,其内容可能是 由map()函数修改。以这种方式,替代案件 问题中描述的内容如下: 1

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

或者更好, 2

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

这个简短的单行完全解决了这个问题。

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

function! Inc(x)
    let a:x[0] += 1
    return a:x[0]
endfunction

并使替换命令更短,

:%s/Id="\zsF\ze"/\=Inc(n)/g

1 这里棘手的部分是在替代部分 替换。由于它以\=开头,因此其余部分被解释为 由Vim表达。因此,'Id="'.map(n, 'v:val+1').'"'是普通的 表达。这里连接了一个字符串文字'Id="'(使用. operator)具有函数调用map(n, 'v:val+1')的返回值,并带有 另一个字符串'"'。函数map需要两个参数:一个列表(如 这种情况)或字典,以及包含表达式的字符串 评估给定列表或字典中的每个项目。特别 变量v:val表示单个列表项。所以'v:val+1'字符串 将被评估为增加一个的列表项。

2 \zs\ze模式原子用于设置开始和 分别替换模式的结尾(参见:help /\zs:help /\ze)。这样,匹配命令的整个搜索部分匹配, 但只有\zs\ze之间的部分被替换。这避免了笨拙 替代表达式中的连接。

答案 1 :(得分:12)

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

:nmap %% :let X=1<cr>1G!!
:nmap !! /^\s*<SomeElement Id="F"<cr>:s/F"/\=X.'"'/<cr>:let X=X+1<cr>!!

一旦有,请按%%启动有趣的部分:)

它使您的给定文件为:

<SomeElement Id="1" ... />
<SomeElement Id="2" ... />
<SomeElement Id="3" ... />
<SomeElement Id="4" ... />

说明:

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

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

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

  • 搜索下一次出现的模式^\s*<SomeElement Id="F"
  • 如果找到上述模式,则按变量F"和引用X
  • 搜索并替换"
  • 将vim变量X增加1
  • 通过拨打!!
  • 递归调用自己
  • 单点.用于连接vim中的字符串,非常类似于php

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

答案 2 :(得分:7)

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

以下示例将PATTERN的所有出现替换为REPLACE_[counter]REPLACE_1REPLACE_2等):

:let i=1 | g/PATTERN/s//\='REPLACE_'.i/ | let i=i+1

要回答这个问题,可能会是这样的:

:let i=1 | g/SomeElement Id="F"/s//\='SomeElement Id="'.i.'"'/ | let i=i+1

答案 3 :(得分:6)

非常简单的解决方案。我必须多次这样做。

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

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

答案 4 :(得分:1)

将其放入vimrc或在当前会话中执行:

function! Inc(x) 
  let a:x[0] += 1 
  return a:x[0] 
endfunction

function IncReplace(pos, behind, ahead, rep) 
  let poss=a:pos-1 
  let n=[poss] 
  execute '%s/' . a:behind . '\zs' . a:rep . '\ze' . a:ahead . '/\=Inc(n)/g' 
endfunction

然后执行:call IncReplace(1, 'Id="', '"', 'F')

第一个参数是您想要开始的数字,第二个参数是您要在数字后面匹配的数字,第三个参数是您希望在数字之前匹配的数字,第四个是您实际想要替换的数字。

答案 5 :(得分:0)

也许plugin increment.vim会有所帮助