Vim: глобальный поиск и замена, начиная с позиции курсора - PullRequest
106 голосов
/ 29 сентября 2011

Когда я выполняю поиск с помощью

/\vSEARCHTERM

Vim начинает поиск с позиции курсора вниз, и он оборачивается вверх.Однако при поиске и замене с использованием

:%s/\vBEFORE/AFTER/gc

Vim начинается в верхней части файла.

Есть ли способ выполнить поиск и замену Vim, начиная с позиции курсора И, переходя квершина, как только он достигает конца?

Ответы [ 6 ]

154 голосов
/ 29 сентября 2011

Вы уже используете диапазон, %, который является сокращением для 1,$, то есть всего файла.Для перехода от текущей строки к концу вы используете .,$.Точка означает текущую строку, а $ означает последнюю строку.Таким образом, команда будет выглядеть так:

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

Но можно предположить, что . или текущая строка может быть удалена:

:,$s/\vBEFORE/AFTER/gc

Для получения дополнительной информации см.

:h range
45 голосов
/ 30 сентября 2011

Нетрудно добиться поведения с помощью двухэтапной подстановки:

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

Сначала для каждой строки запускается команда подстановки, начиная с текущей и до конца файла.Затем эта команда :substitute повторяется с тем же шаблоном поиска, строкой замены и флагами с использованием команды :&.Последний, однако, выполняет подстановку в диапазоне строк от первой строки файла до строки, где была установлена ​​предыдущая метка контекста, минус один.Поскольку первая команда :substitute сохраняет позицию курсора до начала фактической замены, строка, адресуемая '', является строкой, которая была текущей до запуска этой команды замещения.

Обратите внимание, что вторая команда (после символа |) не требует каких-либо изменений при изменении шаблона или флагов первого.

45 голосов
/ 29 сентября 2011

% - это сокращение для 1,$
(Vim help => :help :% равно 1, $ (весь файл).)

. - положение курсора, поэтомуВы можете сделать

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

Заменить с начала документа до курсора

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

и т. д.

Я настоятельно рекомендую вам прочитать руководство по диапазону :help range почти все команды работают с диапазоном.

3 голосов
/ 18 марта 2014

Я НАКОНЕЦ придумал решение для того факта, что выход из поиска оборачивается в начало файла без написания огромной функции ...

Вы не поверите, сколько времени это заняломне придумать это.Просто добавьте подсказку, следует ли переносить: если пользователь снова нажимает 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)
1 голос
/ 03 ноября 2018

Я опоздал на вечеринку, но слишком часто полагался на такие поздние ответчики stackoverflow, чтобы не делать этого. Я собрал подсказки по reddit и stackoverflow, и лучший вариант - использовать шаблон \%>...c в поиске, который соответствует только после вашего курсора.

Тем не менее, он также испортил шаблон для следующего шага замены, и его трудно напечатать. Чтобы противостоять этим эффектам, пользовательская функция должна затем фильтровать шаблон поиска, сбрасывая его. Увидеть ниже.

Я ограничил себя картированием, которое заменяет следующий случай и переходит к следующему после, а не больше (в любом случае, это была моя цель). Я уверен, что, опираясь на это, можно выработать глобальную замену. При работе с решением, нацеленным на что-то вроде :%s/.../.../g, имейте в виду, что приведенный ниже шаблон отфильтровывает совпадения в всех строках, оставленных до позиции курсора, но очищается после завершения одиночной замены, поэтому сразу теряет этот эффект, переходит к следующему матчу и, таким образом, может проходить все матчи один за другим.

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 голос
/ 28 апреля 2016

Вот кое-что очень грубое, что решает проблему оборачивания поиска с помощью двухэтапного подхода (:,$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".
  • Если вы уже записываете макрос при использовании команды, все ставки выключены.
  • Пытается делать правильные вещи с прерываниями.
  • Предотвращает предупреждения о «обратном диапазоне» с явной защитой.
...