在Vim中搜索并替换为递增的值

在Vim中搜索并替换为递增的值,vim,replace,Vim,Replace,假设我编写了一个简单的CSS规则,如下所示: .star_10 { background: url(stars.png) no-repeat 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 -

假设我编写了一个简单的CSS规则,如下所示:

.star_10 {
  background: url(stars.png) no-repeat 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;
}
what 0 0 post
areu 0 0 post
doin 0 0 post
我需要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;
}
等等

现在我想用递增的值来更改星号100,如下所示:

.star_10 {
  background: url(stars.png) no-repeat 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;
}
what 0 0 post
areu 0 0 post
doin 0 0 post
等等


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

您可以使用带有
\=
符号的
s/pattern/replace
构造来计算函数或表达式,如图所示:

递减
.star\u 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带有

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

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

后面的表达式。您可能会为此编写一个函数,但我通常会做一些更简单的事情。我使用涉及^a和^X键的键宏(递增和递减数字)。使用
qa
开始录音,使用带有计数修饰符的按键(例如
18^X
),然后说10@就可以了

您可以使用宏轻松完成此操作。假设您只有以下内容:

.star_10 {
  background: url(stars.png) no-repeat 0 0;
}
将光标放在第一个点上(在
.star10
)并在正常模式下键入以下内容:

qa3yy3jp^Xjt;18^Xk0q
解释:

  • qa
    将在寄存器“a”中启动宏记录
  • 3yy
    将拖动(复制)以下3行
  • 3j
    将光标向下放置3行
  • p
    将粘贴过去拖动的文本
  • ^X
    (ctrl+X)将减少星级编号
  • j
    将光标向下一行
  • t
    将光标放在下一个
    之前在当前行中
  • 18^X
    将使回传的y坐标减少18
  • k
    将光标向上移动一行
  • 0
    将光标置于行的最下方
  • q
    将完成宏录制
  • 在那之后,你可能会有这样的事情

    .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,而不是示例2(这是原始示例)

    我创建了一个名为
    SearchIncr()的函数(搜索、替换和增量)

    有四个必需的参数:
    target\u string
    replacement\u string
    start\u value
    increment\u value
    。 还有两个可选参数:
    前导零
    位置

    前导零
    为正整数值,
    位置
    为“之前”或“之后”。参见示例2


    例1 然后您将获得:

    what new00000001 post
    areu new00000006 post
    doin new00000011 post
    
    .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;
    }
    

    例2 然后您将获得:

    what new00000001 post
    areu new00000006 post
    doin new00000011 post
    
    .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
    
    “将函数放在此处
    函数!搜索增量(a1、a2、a3、a4等)
    “patn,repl,start,increment
    让目标=a:a1
    设repl=a:a2
    设startval=a:a3
    设增量=a:a4
    “第一个可选参数处理前导零
    “进程可选前导零
    如果a:0>=1
    让导线Z=a:1
    其他的
    “默认为0
    设导程z=0
    恩迪夫
    “第二个可选参数处理目标字符串是否在前面或后面
    “违约发生在
    如果a:0==2
    “理想情况下设置为“之后”
    让repl_pos=a:2
    其他的
    让repl_pos='before'
    恩迪夫
    “inits
    设l:incr=startval-增量
    设lnum=a:firstline
    “循环选择
    
    lnum仅使用纯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
    

    这是一个很好的开始@Node17,哦,我用这个技巧在一个文件中重新编号6000帧。。。工作非常出色。关于@rene nyffenegger的答案:有没有一种方法可以将参数(start_value,decrement_value)放入函数中?虽然很多人都在谈论函数、插件等,但宏是vim的真正力量。vim为什么会用最“高级”的语言来扫地的另一个极好的例子IDE对这个答案感到非常高兴——这是我第一次真正了解Vim宏。这对于这个CSS片段来说非常具体,但我认为它可以通过一些工作适应其他事情。这个答案与OPs数据非常相关,他在OPs数据中反复使用相同的数字。我会问一个标题文字相同的问题,可能会以重复的方式结束,但我的数据在每一场比赛中都有不同的数字,只是模式相同。很难猜测用什么来代替
    ^x
    有没有一种方法可以在函数中放置参数(开始、递减值)?