Programming

Vim : 커서 위치에서 시작하여 전역 검색 및 바꾸기

procodes 2020. 8. 3. 09:01
반응형

Vim : 커서 위치에서 시작하여 전역 검색 및 바꾸기


내가 검색 할 때

/\vSEARCHTERM

Vim은 커서 위치에서 아래쪽으로 검색을 시작하고 위쪽으로 둘러 쌉니다. 그러나 검색 및 교체시

:%s/\vBEFORE/AFTER/gc

Vim은 파일 맨 위에서 시작합니다.

커서 위치에서 시작하여 Vim을 검색하고 바꾸고 끝에 도달하면 상단을 감싸는 방법이 있습니까?


2 단계 대체를 사용하여 동작을 달성하는 것은 어렵지 않습니다.

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

먼저, 현재 행에서 시작하여 파일 끝까지 각 행에 대해 대체 명령이 실행됩니다. 그런 다음 :substitute명령을 사용하여 동일한 검색 패턴, 대체 문자열 및 플래그를 사용하여 해당 명령을 반복합니다 :&. 그러나 후자는 파일의 첫 번째 행에서 이전 컨텍스트 표시가 설정된 행 (빼기 1)까지 행 범위에서 대체를 수행합니다. 첫 번째 :substitute명령은 실제 ​​교체를 시작하기 전에 커서 위치를 저장 하기 때문에 주소 ''가 지정된 행은 대체 명령이 실행되기 전의 행이었습니다.

두 번째 명령 ( |기호 )은 첫 번째 명령의 패턴이나 플래그가 변경 될 때 변경이 필요하지 않습니다.


이미 전체 파일 %1,$의미하는 짧은 손인 range를 사용하고 있습니다. 현재 줄에서 끝까지 가려면 .,$. 마침표는 현재 줄을 $의미하고 마지막 줄을 의미합니다. 따라서 명령은 다음과 같습니다.

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

그러나 .현재 또는 현재 줄을 제거 할 수 있다고 가정 할 수 있습니다.

:,$s/\vBEFORE/AFTER/gc

도움이 더 필요하면

:h range

%에 대한 바로 가기입니다 1,$
(=> 빔 도움말 :help :%1, $ (전체 파일)와 동일.)

. 당신이 할 수있는 커서 위치입니다

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

문서의 처음부터 커서까지 교체

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

기타

:help range거의 모든 명령이 범위에서 작동하므로 범위에 대한 설명서를 읽는 것이 좋습니다 .


나는 마지막으로 검색을 끝내는 것이 엄청난 기능을 쓰지 않고 파일의 시작 부분을 감싸는 사실에 대한 해결책을 찾았습니다 ...

당신은 이것을 생각해 내는데 얼마나 오래 걸 렸는지 믿지 않을 것입니다. 랩핑할지 묻는 메시지를 추가하기 만하면됩니다. 사용자가 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)

다음 은 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

이 함수는 몇 가지 핵을 사용하여 맨 위로 감쌀 지 여부를 확인합니다.

  • No wrapping if user pressed "l", "q" or "Esc", any of which indicate a desire to abort.
  • Detect that final key press by recording a macro into the "s" register and inspecting last character of it.
  • Avoid overwriting an existing macro by saving/restoring the "s" register.
  • If you are already recording a macro when using the command, all bets are off.
  • Tries to do the right thing with interrupts.
  • Avoids "backwards range" warnings with an explicit guard.

I am late to the party, but I relied too often on such late stackoverflow answerrs to not do it. I gathered hints on reddit and stackoverflow, and the best option is to use the \%>...c pattern in the search, which matches only after your cursor.

That said, it also messes up the pattern for the next replacement step, and is hard to type. To counter those effects, a custom function must filter the search pattern afterwards, thus resetting it. See below.

I have contended myself with a mapping that replaces the next occurence and jumps to the following after, and not more (was my goal anyway). I am sure, building on this, a global substitution can be worked out. Keep in mind when working on a solution aiming at something like :%s/.../.../g that the pattern below filters out matches in all lines left to the cursor position -- but is cleaned up after the single substitution completes, so it loses that effect directly after, jumps to the next match and thus is able to run through all matches one by one.

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

참고URL : https://stackoverflow.com/questions/7598133/vim-global-search-replace-starting-from-the-cursor-position

반응형