2009-11-27 17 views
5

Ben bir vim kullanıcısıyım ve yerine koyduğumda bir dizi alt dizgiyi birleştirmek istiyorum. Nasıl böyle bir dizi çizgi gitmek için bazı vim büyü kullanabilirsiniz:VIM'de dizelerin bir listesini nasıl değiştirebilirim?

Afoo 
Bfoo 
Cfoo 
Dfoo 

Abar 
Bbar 
Cbaz 
Dbaz 

için?

Ben foo sonraki bulunduğu yerde baştan dosyamı arama ve bar ile ilk iki örneklerini değiştirmek istiyor ve baz ile ikinci iki. For döngüsünü en iyi seçenek kullanıyor mu? Eğer öyleyse, o zaman döngü değişkenini ikame komutunda nasıl kullanırım?

cevap

9

Durumu olan bir işlevi kullanır ve bu işlevi% s olarak adlandırır. gibi bir şey:

" 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 

Ve bunları kullanın: İsterseniz iki komutlara

:call InitRotateSubst() 
:%s/foo/\=RotateSubst(['bar', 'bar', 'baz', 'baz'])/ 

çağrı tek komutla içine kapsüllü olabilir.


DÜZENLEME: Biz, tüm yenilemeler ayırıcı-karakteri ile ayrılması gerekir istedikleri gibi

  • gibi birçok değiştirmeler kabul etmektedir: Burada bir komut olarak entegre edilmiş bir versiyonudur
  • , geri referansları destekler; Sadece N ilk olaylar yerini alabilir
  • , N (a ile!) komutu çağrı çarptım ise belirtilen değiştirmelerin sayısını ==
  • g gibi olağan bayraklarını desteklemez i (:h :s_flags) - bunun için, Örneğin, son metnin bayrak olarak yorumlanmaması durumunda, komut çağrısını her zaman bir/(veya herhangi bir ayırıcı karakterle) ile sona erdirmek zorunda kalırdık.Burada

komut tanımı: bile

:%RotateSubstitute#foo#bar#bar#baz#baz# 

veya, ilk metin dikkate:

AfooZ 
BfooE 
CfooR 
DfooT 

komutu, bu şekilde kullanılabilir

: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\(.\)/\2bar\1/\1bar\2/ 

üretecektir:

ZbarA 
BbarE 
RbarC 
DbarT 
0

Muhtemelen ilk ikisinin yerini alabilecek bir makroyu kaydetmek çok daha kolay olacak ve ardından geri kalanlar için s: kullanımı çok daha kolay olacaktır.

Makro, /foo^Mcwbar^[ gibi görünebilir. Makro modunu bilmiyorsanız, q, a (saklamak için kaydet) ve ardından /foo <Enter> cwbar <Escape> tuş vuruşlarına basın. O makro var bir kere

Şimdi, geçerli tampon ilk iki tekrarlarını değiştirmek ve dinlenme yerine normal :s kullanmak [email protected] yok.

1

Bu makroyu nasıl denemeliyim.

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. 

Nasıl daha iyi yapılacağına dair herhangi bir öneri memnuniyetle karşılanır.

Teşekkürler, Martin.

+0

Görünüşe göre, nihayetinde bir "n" eksiksiniz. ' – Rich

2

İstediğin ancak döngüleri için yararlı olabilir Ne kesinlikle Değildir.

Eklenti swapit http://www.vim.org/scripts/script.php?script_id=2294 yazdım. Örneğin.

:Swaplist foobar foo bar baz 

sonra

This line is a foo 

, basit bir yank/yapıştırma hattını oluşturmak son kelime ve ctrl-a takas gidin yazın.

qqyyp$^A 

sonra Muhtemelen onun {cword} hassas olmasına rağmen sorununuza uygulanabilir

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 
... 

almak için takas deseni

[email protected] 

yürütün.

2

Neden:

:%s/\(.\{-}\)foo\(\_.\{-}\)foo\(\_.\{-}\)foo\(\_.\{-}\)foo/\1bar\2bar\3baz\4baz/ 

Ben sorunun genişliği kapsamaktadır ancak basit bir yedek olma erdemini var olduğundan emin değilim. Daha karmaşık olanı, eğer bu yoksa, çözümü kapsayabilir.

+0

Hey Derek, Sadece vim videolarınızdan bazılarını vimeo'da izledim. Sadece onları izlemekten zevk aldığımı ve birkaç şey öğrendiğimi söylemek istedim. Çözümünüz, regex ile biraz daha iyi olsaydım, ulaşabileceğim şeydir. Bu basit çözüm için teşekkürler. – Ksiresh

İlgili konular