我是vim的用戶,我希望能夠在代替時遍歷一系列子字符串。我如何可以使用一些魔法的vim從這樣一組線走:如何從VIM中的字符串列表中進行替換?
Afoo
Bfoo
Cfoo
Dfoo
到
Abar
Bbar
Cbaz
Dbaz
?
我想從下一次出現foo
開始搜索我的文件,並用bar
替換前兩個實例,用baz
替換前兩個實例。使用for循環是最好的選擇?如果是這樣,那麼我如何在替代命令中使用循環變量?
我是vim的用戶,我希望能夠在代替時遍歷一系列子字符串。我如何可以使用一些魔法的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'])/
的調用兩個命令可以被封裝成一個單一的命令。
編輯:這裏是集成爲一個命令一個版本:
: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
命令
3210會產生:
它可能會要容易得多錄製宏,可替換的前兩個,然後用:S爲休息。
宏可能看起來像/foo^Mcwbar^[
。如果您對宏模式不熟悉,只需點擊q
,a
(將其存儲在該寄存器中),然後點擊擊鍵/foo <Enter> cwbar <Escape>
。
現在,一旦您獲得了該宏,請執行[email protected]
來替換當前緩衝區中的前兩個事件,並通常使用:s
來替換其他緩衝區。
這是我如何嘗試這個宏。
qa Records macro in buffer a
/foo<CR> Search for the next instance of 'foo'
3s Change the next three characters
bar To the word bar
<Esc> Back to command mode.
n Get the next instance of foo
. Repeat last command
n Get the next instance of foo
3s Change next three letters
baz To the word bar
<Esc> Back to command mode.
. Repeat last command
q Stop recording.
[email protected] Do a many times.
任何關於如何做得更好的建議是值得歡迎的。
謝謝, Martin。
這並不是嚴格的,你想要什麼,但能爲週期是有用的。
我寫了一個插件swapit http://www.vim.org/scripts/script.php?script_id=2294除其他東西都可以通過字符串列表與循環幫助。例如。
:Swaplist foobar foo bar baz
然後鍵入
This line is a foo
創建一個簡單的抽出/貼線,去最後一個字和Ctrl-交換。
qqyyp$^A
然後執行交換模式
[email protected]
得到
This line is foo
This line is bar
This line is baz
This line is foo
This line is bar
This line is baz
This line is foo
This line is bar
This line is baz
This line is foo
This line is bar
This line is baz
...
它很可能被應用到你的問題雖然其{} cword敏感。
爲什麼不:
:%s/\(.\{-}\)foo\(\_.\{-}\)foo\(\_.\{-}\)foo\(\_.\{-}\)foo/\1bar\2bar\3baz\4baz/
我不知道它涵蓋了問題的廣度,但確實有憑藉的是一個簡單的替代品。如果這個問題沒有解決,則更復雜的解決方案可能會涵蓋解決方案
嘿德里克, 只是想說我昨天在vimeo上觀看了一些你的vim視頻。我只想說我喜歡看他們,並且學習了一些東西。 如果我用正則表達式更好一些,你的解決方案就是我所能達到的。感謝這個簡單的解決方案。 – Ksiresh 2009-12-18 13:12:48
看起來像是你在最後的''n'之前缺少'。' – Rich 2018-02-26 09:52:45