gpt4 book ai didi

vim - 如何从 VIM 中的字符串列表进行替换?

转载 作者:行者123 更新时间:2023-12-04 16:49:57 24 4
gpt4 key购买 nike

我是 vim 用户,我希望在替换时能够遍历一系列子字符串。我怎样才能使用一些 vim 魔法从这样的一组行中走出来:

Afoo
Bfoo
Cfoo
Dfoo


Abar
Bbar
Cbaz
Dbaz

?

我想从头开始搜索我的文件以查找下一次出现 foo ,并将前两个实例替换为 bar ,第二个是 baz .使用 for 循环是最好的选择吗?如果是这样,那么如何在替换命令中使用循环变量?

最佳答案

我会使用一个有状态的函数,并从 %s 调用这个函数。就像是:

" untested code
function! InitRotateSubst()
let s:rs_idx = 0
endfunction

function! RotateSubst(list)
let res = a:list[s:rs_idx]
let s:rs_idx += 1
if s:rs_idx == len(a:list)
let s:rs_idx = 0
endif
return res
endfunction

并将它们用于:
:call InitRotateSubst()
:%s/foo/\=RotateSubst(['bar', 'bar', 'baz', 'baz'])/

如果您愿意,可以将这两个命令的调用封装到一个命令中。

编辑:这是一个集成为命令的版本:
  • 接受尽可能多的替换,所有替换都需要用分隔符分隔;
  • 支持反向引用;
  • 只能替换第一次出现的 N,N == 指定的替换次数,如果命令调用被破坏(带有 !)
  • 不支持像 g, i ( :h :s_flags ) 这样的常见标志——为此,我们必须例如将命令调用强加到总是以/(或任何分隔符)结尾,如果不是最后一个文本是解释为标志。

  • 下面是命令定义:
    :command! -bang -nargs=1 -range RotateSubstitute <line1>,<line2>call s:RotateSubstitute("<bang>", <f-args>)

    function! s:RotateSubstitute(bang, repl_arg) range
    let do_loop = a:bang != "!"
    " echom "do_loop=".do_loop." -> ".a:bang
    " reset internal state
    let s:rs_idx = 0
    " obtain the separator character
    let sep = a:repl_arg[0]
    " obtain all fields in the initial command
    let fields = split(a:repl_arg, sep)

    " prepare all the backreferences
    let replacements = fields[1:]
    let max_back_ref = 0
    for r in replacements
    let s = substitute(r, '.\{-}\(\\\d\+\)', '\1', 'g')
    " echo "s->".s
    let ls = split(s, '\\')
    for d in ls
    let br = matchstr(d, '\d\+')
    " echo '##'.(br+0).'##'.type(0) ." ~~ " . type(br+0)
    if !empty(br) && (0+br) > max_back_ref
    let max_back_ref = br
    endif
    endfor
    endfor
    " echo "max back-ref=".max_back_ref
    let sm = ''
    for i in range(0, max_back_ref)
    let sm .= ','. 'submatch('.i.')'
    " call add(sm,)
    endfor

    " build the action to execute
    let action = '\=s:DoRotateSubst('.do_loop.',' . string(replacements) . sm .')'
    " prepare the :substitute command
    let args = [fields[0], action ]
    let cmd = a:firstline . ',' . a:lastline . 's' . sep . join(args, sep)
    " echom cmd
    " and run it
    exe cmd
    endfunction

    function! s:DoRotateSubst(do_loop, list, replaced, ...)
    " echom string(a:000)
    if ! a:do_loop && s:rs_idx == len(a:list)
    return a:replaced
    else
    let res0 = a:list[s:rs_idx]
    let s:rs_idx += 1
    if a:do_loop && s:rs_idx == len(a:list)
    let s:rs_idx = 0
    endif

    let res = ''
    while strlen(res0)
    let ml = matchlist(res0, '\(.\{-}\)\(\\\d\+\)\(.*\)')
    let res .= ml[1]
    let ref = eval(substitute(ml[2], '\\\(\d\+\)', 'a:\1', ''))
    let res .= ref
    let res0 = ml[3]
    endwhile

    return res
    endif
    endfunction

    可以这样使用:
    :%RotateSubstitute#foo#bar#bar#baz#baz#

    甚至,考虑初始文本:
    AfooZ
    BfooE
    CfooR
    DfooT

    命令
    %RotateSubstitute/\(.\)foo\(.\)/\2bar\1/\1bar\2/

    会产生:
    ZbarA
    BbarE
    RbarC
    DbarT

    关于vim - 如何从 VIM 中的字符串列表进行替换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1809571/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com