2017-08-13 10 views
0
function! Reduce() 
    let ls=getpos("'<") 
    let lsp=ls[1] 
    let tvar = '\<' . @* 
    echom tvar 

    for i in range(1,30) 
     let ssv=getline(lsp+i-1) 
     let t1=matchstr(ssv,tvar) 
     echom t1 
     if t1 =~ @* 
     echom ssv 
     delete 
     endif 
    endfor 
endfun 

上記のスクリプトで私を助けてもらえますか? このスクリプトの問題点は何ですか。 if条件を削除して単純にssvを出力すると、 と一致する30文字の文字列をすべて表示しますが、削除コマンドを実行すると、少数の文字列に対してのみ一致します。 "delete"コマンドの代わりに "normal!dd"と同じ動作を試して検証しました。gvimスクリプトが削除で正常に動作しない

答えて

2

forループでgetlineを使用し、相対行番号としてiを使用します。そして、ループ内の行を削除します。何ここで起こってことです:あなたはLINE2を削除

line1 
line2 <- i = 2 
line3 
line4 

line1 
line3 <- i = 2 
line4 

その後forループ増加i

line1 
line3 
line4 <- i = 3 

ので、次の処理された行はline4、あなたが期待通りではないline3です。

はそれがすなわち、最初に端から行を削除し、逆方向に rangeを実行解決する:

for i in range(30, 1, -1) 
1

博士が言ったように、あなたの反復の方向を逆にする必要があります。

パフォーマンス上の理由から、ここではforループを避ける方が好きです。もしあなたが何千もの行を持っていたら(私は知っている、あなたは30だけしか持っていない)、あなたは違いを感じていたでしょう。

私はそれをこのように書きます(場合には、私は:deleteよりも複雑なものが必要):ネイティブ(と非常に効率的な)と比較した場合、

" untested 
let first_line = line("'<") 
" 1- extract all lines in the range 
let lines= getline(first_line, first_line+30) " or 29 ? 
" 2- convert lines into line numbers, or -1 if not matching 
let matching_line_nrs = map(lines, 'match(v:val, tvar)>=0 ? v:key : -1') 
" 3- keep the positive ones 
call filter(matching_line_nrs, 'v:val > 0') 
" 4- and finally remove the matching lines, in reserve order 
" NB: I though there was a deleteline() function, but couldn't find any 
" trace of it, hence execute(linenr.'delete') 
call map(reverse(matching_line_nrs), 'execute(v:val."delete")') 

かなり複雑である

:exe "'<".',+29g/\<'[email protected]*.'/d' 

または、対話型で入力した場合

:'<,+29g/\<^R*/d_ 
" With ^R being CTRL-R 
関連する問題