在Vim中使用递增值搜索和替换

时间:2011-02-09 22:52:28

标签: vim replace

假设我写了一个简单的CSS规则:

.star_10 {
  background: url(stars.png) no-repeat 0 0;
}

我需要10次,所以我复制了9次。

.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_10 {
  background: url(stars.png) no-repeat 0 0;
}

现在我想用增量值更改 star_10 0 0 ,所以它看起来像这样:

.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_9 {
  background: url(stars.png) no-repeat 0 -18px;
}
.star_8 {
  background: url(stars.png) no-repeat 0 -36px;
}
.star_7 {
  background: url(stars.png) no-repeat 0 -54px;
}

依旧......

那么如何搜索/替换每个实例,进行计算并编写呢?

5 个答案:

答案 0 :(得分:57)

您可以使用宏轻松完成。让我们说你只有这个:

.star_10 {
  background: url(stars.png) no-repeat 0 0;
}

将光标放在第一个点(.star10)上,然后在正常模式下键入以下内容:

qa3yy3jp^Xjt;18^Xk0q

解释

  1. qa将在注册“a”中启动宏录制。
  2. 3yy会猛拉(复制)以下3行。
  3. 3j会将光标放下3行。
  4. p会粘贴过去的文字。
  5. ^X(ctrl + x)将减少星级编号。
  6. j会将光标放下一行。
  7. t;会将光标放在当前行中的下一个;之前。
  8. 18^X会将背景的y坐标减少18;
  9. k会将光标放一行,
  10. 0会将光标放在行的开头。
  11. q将完成宏录制。
  12. 之后,你可能会有这样的事情。

    .star_10 {
      background: url(stars.png) no-repeat 0 0;
    }
    
    .star_9 {
      background: url(stars.png) no-repeat 0 -18;
    }
    

    就是这样。只需将光标放在.star_9上的点上,然后按8@a再次执行寄存器a中记录的宏八次。

答案 1 :(得分:13)

您可以将s/pattern/replace构造与\=符号一起使用,以评估函数或表达式,如下所示:

减少.star_10

let g:decr = 11

fu! Decr() 
  let g:decr = g:decr - 1
  return g:decr
endfu

:%s/.star_10/\=".star_" . Decr()/

同样,你要做

let g:decr_18 = 18
fu! Decr18() 
  let g:decr_18 = g:decr_18 - 18
  return g:decr_18
endfu

然后用

替换0 0;
:%s/no-repeat 0 0;/\="no-repeat 0 " . Decr18() . "px"/

对于这两个函数,声明一个(全局)变量,该变量在函数内被操作并返回。对于与模式匹配的每一行,都会调用功能区本身。该模式将替换为\=之后的表达式。

答案 2 :(得分:2)

你可能会为此编写一个函数,但我通常会做一些更简单的事情。我使用一个涉及^ A和^ X键的关键宏(递增和递减一个数字)。使用qa开始录制,做你的东西,使用带有计数修饰符的那些键(例如18^X),然后说,10 @ after。

答案 3 :(得分:0)

我需要这个解决方案,但也需要领先的零支持。我对原始问题的使用更像是示例1而不是示例2(这是原始示例)。

我创建了一个名为SearchIncr() (search, replace, and increment)的函数。

有四个必需参数:target_stringreplacement_stringstart_valueincrement_value。 还有两个可选参数:leading_zerosposition

leading_zeros是正整数值,position是'之前'或'之后'。见例2.


示例1

:'<,'>call SearchIncr("0 0","new",1,5,8)

如果文件如下所示:

what 0 0 post
areu 0 0 post
doin 0 0 post

然后你会得到:

what new00000001 post
areu new00000006 post
doin new00000011 post

示例2

:'<,'>call SearchIncr("0;","px;",-18,-18,0,'after')

如果文件如下所示:

.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
.star_10 {
  background: url(stars.png) no-repeat 0 0;
}

然后你会得到:

.star_10 {
  background: url(stars.png) no-repeat 0 -18px;
}
.star_10 {
  background: url(stars.png) no-repeat 0 -36px;
}
.star_10 {
  background: url(stars.png) no-repeat 0 -54px;
}

vimscript在这里:

" place functions here
function! SearchIncr(a1,a2,a3,a4,...) 
  " patn, repl, start, increment
  let target = a:a1
  let repl = a:a2
  let startval = a:a3
  let increment = a:a4

  " 1st optional argument handles leading zeros
  " process optional leading zero
  if a:0 >= 1
    let leadingz = a:1
  else
    " default to 0
    let leadingz = 0
  endif

  " 2nd optional argument handles if target string goes before or after
  " default is before
  if a:0 == 2
    " ideally set to 'after'
    let repl_pos = a:2 
  else
    let repl_pos = 'before'
  endif

  " inits
  let l:incr = startval - increment
  let lnum = a:firstline

  " cycle though selection
  while lnum <= a:lastline

    " the FORMATTING string
    if repl_pos == 'before'
      let l:incrstring = '\=printf(''%s%0'. leadingz . 'd'',repl,l:incr)'
    elseif repl_pos == 'after'
      let l:incrstring = '\=printf(''%0'. leadingz . 'd%s'',l:incr,repl)'
    else
      "default to no leading zero and before placement
      let l:incrstring = '\=printf(''%s%0d'',repl,l:incr)'
    endif

    " only increment counter when target matches
    if match(getline(lnum),target) > 0
      let l:incr = l:incr + increment
    endif

    " the search and replace
    call setline(lnum,substitute(getline(lnum),target,
    \ l:incrstring,'g'))

    let lnum = lnum + 1
  endwhile
endfunction

任何改进上述内容的评论都将不胜感激!

答案 4 :(得分:0)

仅使用纯vim资源,无需编写脚本:

:let c=10 | g/_\zs\d\+\ze/ s//\=c/ | let c-=1 
:let c=0 | g/no-repeat 0 \zs\d\+/ s//\=c/ | let c-=18