web-dev-qa-db-ja.com

Vim:カーソル位置から始まるグローバル検索と置換

で検索するとき

/\vSEARCHTERM

Vimはカーソル位置から下に向かって検索を開始し、上に折り返します。ただし、検索と置換を使用して

:%s/\vBEFORE/AFTER/gc

Vimはファイルの先頭から始まります。

Vimをカーソル位置から検索して置換し、最後に到達したら先頭に折り返す方法はありますか?

108
basteln

2段階の置換を使用して動作を実現するのは難しくありません。

:,$s/BEFORE/AFTER/gc|1,''-&&

最初に、現在の行からファイルの終わりまでの各行に対して置換コマンドが実行されます。次に、:substituteコマンドを使用して、同じ検索パターン、置換文字列、およびフラグを使用して、その:&コマンドを繰り返します。ただし、後者は、ファイルの最初の行から前のコンテキストマークが設定されている行から1を引いた行までの行の範囲で置換を実行します。最初の:substituteコマンドは実際の置換を開始する前にカーソル位置を保存するため、''でアドレス指定された行は、その置換コマンドが実行される前の現在の行でした。

2番目のコマンド(|シンボルの後)は、最初のコマンドまたはパターンのフラグが変更されたときに変更を必要としないことに注意してください。

46
ib.

既に%の範囲を使用しています。これは、ファイル全体を意味する1,$の省略形です。現在の行から最後まで移動するには、.,$を使用します。ピリオドは現在の行を意味し、$は最後の行を意味します。したがって、コマンドは次のようになります。

:.,$s/\vBEFORE/AFTER/gc

ただし、.または現在の行は想定されるため、削除できます。

:,$s/\vBEFORE/AFTER/gc

詳細については

:h range
155
Peter Rincker

%1,$のショートカットです
(Vimヘルプ=> :help :%は1、$(ファイル全体)に等しい。)

.はカーソル位置であるため、次のことができます。

:.,$s/\vBEFORE/AFTER/gc

ドキュメントの先頭からカーソルまでを置換するには

:1,.s/\vBEFORE/AFTER/gc

ほぼすべてのコマンドが範囲で機能するため、範囲:help rangeに関するマニュアルを読むことを強くお勧めします。

46
mb14

私は最終的に、膨大な関数を作成せずに検索を終了するとファイルの先頭に戻るという事実の解決策を思い付きました...

あなたは私がこれを思い付くのにどれくらい時間がかかったかを信じないでしょう。単にラップするかどうかを確認するプロンプトを追加します。ユーザーがqを再度押してもラップしないでください。基本的に、qqの代わりにqをタップして検索を終了します! (そして、ラップしたい場合は、単にyと入力してください。)

:,$s/BEFORE/AFTER/gce|echo 'Continue at beginning of file? (y/q)'|if getchar()!=113|1,''-&&|en

私は実際にこれをホットキーにマッピングしています。したがって、たとえば、現在の位置からカーソルの下のすべての単語を検索してq*に置き換える場合:

exe 'nno q* :,$s/\<<c-r>=expand("<cword>")<cr>\>//gce\|echo "Continue at beginning of file? (y/q)"\|if getchar()==121\|1,''''-&&\|en'.repeat('<left>',77)
3
q335r49

私はパーティーに遅れていますが、そうしないために、このような遅いstackoverflow answerrsに頼りすぎました。 redditとstackoverflowに関するヒントを集めましたが、最適なオプションは、カーソルの後にのみ一致する_\%>...c_パターンを検索で使用することです。

そうは言っても、次の置換ステップのパターンを台無しにし、入力するのは困難です。これらの効果に対抗するには、カスタム関数は後で検索パターンをフィルタリングして、リセットする必要があります。下記参照。

私は次の出来事に取って代わり、それ以降ではなく次の事柄にジャンプするマッピングで自分自身と競合しました(とにかく私の目標は)。私はこれに基づいて、グローバルな代替が解決できると確信しています。 _:%s/.../.../g_のようなものを目指してソリューションを作成する場合は、以下のパターンがallカーソル位置までの行を除外しますが、単一の置換が完了するとクリーンアップされることに注意してください、そのため、その効果はすぐに失われ、次のマッチにジャンプして、すべてのマッチを1つずつ実行することができます。

fun! g:CleanColFromPattern(prevPattern) return substitute(a:prevPattern, '\V\^\\%>\[0-9]\+c', '', '') endf nmap <F3>n m`:s/\%><C-r>=col(".")-1<CR>c<C-.r>=g:CleanColFromPattern(getreg("/"))<CR>/~/&<CR>:call setreg("/", g:CleanColFromPattern(getreg("/")))<CR>``n

1
simlei

以下は、検索を 2段階アプローチ:,$s/BEFORE/AFTER/gc|1,''-&&)または中間 "ファイルの先頭で続行しますか?" アプローチ:

" Define a mapping that calls a command.
nnoremap <Leader>e :Substitute/\v<<C-R>=expand('<cword>')<CR>>//<Left>

" And that command calls a script-local function.
command! -nargs=1 Substitute call s:Substitute(<q-args>)

function! s:Substitute(patterns)
  if getregtype('s') != ''
    let l:register=getreg('s')
  endif
  normal! qs
  redir => l:replacements
  try
    execute ',$s' . a:patterns . 'gce#'
  catch /^Vim:Interrupt$/
    return
  finally
    normal! q
    let l:transcript=getreg('s')
    if exists('l:register')
      call setreg('s', l:register)
    endif
  endtry
  redir END
  if len(l:replacements) > 0
    " At least one instance of pattern was found.
    let l:last=strpart(l:transcript, len(l:transcript) - 1)
    " Note: type the literal <Esc> (^[) here with <C-v><Esc>:
    if l:last ==# 'l' || l:last ==# 'q' || l:last ==# '^['
      " User bailed.
      return
    endif
  endif

  " Loop around to top of file and continue.
  " Avoid unwanted "Backwards range given, OK to swap (y/n)?" messages.
  if line("''") > 1
    1,''-&&"
  endif
endfunction

この関数は、いくつかのハックを使用して、先頭に折り返す必要があるかどうかを確認します。

  • ユーザーが「l」、「q」、または「Esc」を押した場合、折り返しはありません。これらはいずれも中止を希望することを示します。
  • マクロを「s」レジスタに記録し、その最後の文字を調べることにより、その最後のキー押下を検出します。
  • 「s」レジスタを保存/復元することにより、既存のマクロを上書きしないでください。
  • コマンドの使用時にすでにマクロを記録している場合、すべてのベットはオフになります。
  • 割り込みで正しいことをしようとします。
  • 明示的なガードを使用して、「後方範囲」警告を回避します。
1
wincent