Vim поиск и замена выделенного текста


109

Скажем, у нас есть текст, я вхожу в визуальный режим и выделяю текст. Как быстро найти выделенный текст и заменить его другим?

Ответы:


136

Попробуйте выполнить следующее или введите в свой .vimrc

vnoremap <C-r> "hy:%s/<C-r>h//gc<left><left><left>

При нажатии ctrl+ rв визуальном режиме вам будет предложено ввести текст для замены. Нажмите, enterа затем подтвердите каждое изменение, с которым вы согласны yили отклоняете n.

Эта команда переопределит ваш регистр, hчтобы вы могли выбрать другой (заменив hкоманду выше на другую строчную букву), которую вы не используете.


13
Если вы опустите cin gc, замена выполняется сразу во всем буфере. Если вы допустили ошибку и хотите ее исправить, просто введите uкоманду в командном режиме. Мне этот подход нравится больше, чем подтверждение каждой из замен (что происходит с cмодификатором).
Niloct

3
vmap * y:let @/ = @"<CR>выделено выделено.
kev

8
В чем цель <left><left><left>?
aymericbeaumet 04

7
@aymericbeaumet, чтобы поместить курсор между двумя косыми чертами, чтобы можно было легко ввести слово замены.
mcabrams 03

5
Обратите внимание: если вы примете предложение @Niloct об удалении cиз gc, вам также придется удалить один из символов <left>в конце строки.
Nathan Friend

36

Этот быстрый и простой поиск по отображению для визуально выделенного текста (без перезаписи регистра h) и без использования зависимого от терминала регистра +:

" search for visually hightlighted text
vnoremap <c-f> y<ESC>/<c-r>"<CR>   

Если вам не нравится ctrl-f, измените его по своему усмотрению

Как только текст выделен, вы всегда можете выполнить sзамену, просто набрав:

%s//<your-replacement-string>

... потому что пустой поиск в sкоманде использует последнюю искомую строку.


Когда я использую это в своей конфигурации vim, control+fвсегда выбирает следующий символ, а также то, что я выбрал визуально. Любые идеи?
Роберт Марк Брэм

%s//<your-replacement-string>похоже, не работает для выделения чего-то вроде /tmp/file. это просто становится<your-replacement-string>/tmp/file
naisanza

29

Этот также работает (по крайней мере, для выделений в одной строке / выделений, которые не содержат никаких специальных символов)

  • выделите текст в визуальном режиме
  • выдернуть текст с помощью y
  • :s/<C-r>0/

0 это регистр восстановления.

Как отмечали другие люди, есть более быстрые способы сделать это, но если вы только начали изучать Vim (как и я), это один из «общих» способов.

// редактировать: я только что понял, что подход «регистр» потерпит неудачу, если /в выделении есть символы, такие как табуляция, новая строка или символы (мне пришлось бы как-то вручную обработать эти символы, чтобы :sкоманда работала):

введите описание изображения здесь


2
Все очень просто. О боже, почему это не описано в вики. Давай ... Спасибо за ответ!
Беньямин Лиманто,

2
Это идеальный ответ для тех из нас, кто еще только начинает изучать Vim. Я знаю, что настройка - это сильная сторона, но я не хочу копировать и вставлять сложный скрипт в свой vimrc и ломать голову над тем, как они подходят для такой простой проблемы. Этот ответ научил меня, что ctrl-R выгружает регистр, что будет удобно помнить в других контекстах.
nivek

26

Принятый ответ отлично работает, если у вас нет специальных символов в вашем визуальном выборе. Я собрал вместе два сценария ( Джереми Кантрелла и Питера Оддинга ), чтобы создать команду, которая позволит вам визуально выбрать строку, которую вы хотите найти, даже если в ней есть специальные символы регулярного выражения.

" Escape special characters in a string for exact matching.
" This is useful to copying strings from the file to the search tool
" Based on this - http://peterodding.com/code/vim/profile/autoload/xolox/escape.vim
function! EscapeString (string)
  let string=a:string
  " Escape regex characters
  let string = escape(string, '^$.*\/~[]')
  " Escape the line endings
  let string = substitute(string, '\n', '\\n', 'g')
  return string
endfunction

" Get the current visual block for search and replaces
" This function passed the visual block through a string escape function
" Based on this - /programming/676600/vim-replace-selected-text/677918#677918
function! GetVisual() range
  " Save the current register and clipboard
  let reg_save = getreg('"')
  let regtype_save = getregtype('"')
  let cb_save = &clipboard
  set clipboard&

  " Put the current visual selection in the " register
  normal! ""gvy
  let selection = getreg('"')

  " Put the saved registers and clipboards back
  call setreg('"', reg_save, regtype_save)
  let &clipboard = cb_save

  "Escape any special characters in the selection
  let escaped_selection = EscapeString(selection)

  return escaped_selection
endfunction

" Start the find and replace command across the entire file
vmap <leader>z <Esc>:%s/<c-r>=GetVisual()<cr>/

Я включил это в свой vimrc, если это кому-то более полезно.


2
спасибо за решение, объединив несколько предложений, я получил следующее: vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left>(которое просто заменяет все в файле)
Питер Буткович

13

В Vim 7.4 вы можете использовать gnдвижение, которое выбирает области текста, соответствующие текущему шаблону поиска.

После использования cgnдля изменения текста в текущем выбранном совпадении (или dgnдля удаления) в нормальном режиме вы можете использовать его .для повторения команды и работы со следующим совпадением.

Есть эпизод Vimcast, показывающий эту функцию.


3
Это отличный ответ!
mauriciojost

Это тоже круто. помимо ответа колемика. Великий!
Беньямин Лиманто,

вау, это похоже на один из тех секретов, которые вы обнаруживаете, когда углубляетесь в поисках хорошего решения, спасибо!
vdegenne

8

Николай Голубев, Спасибо за наводку! Далее используется регистр «+», который (в зависимости от вашего терминала) уже содержит выделенный текст, за исключением использования регистра «h».

vnoremap <C-r> <Esc>:%s/<C-r>+//gc<left><left><left>

Мой VIM 7.0 на CentOS 5.x, похоже, не имеет регистра +. Это стандартная функция?
dotancohen

3
Я отмечаю, что получаю доступ к машине CentOS через Putty, и после поиска в Google я вижу, что + - это регистр буфера обмена. Putty, похоже, не поддерживает это! Так что этот ответ фактически зависит от терминала.
dotancohen

Привет, я попробовал вашу команду, но она просит меня заменить вхождения указанного текста во всем файле, а не только в выделенном тексте
solalito

7

Из http://vim.wikia.com/wiki/Search_and_replace_in_a_visual_selection :

Когда текст выделен визуально, нажмите: для ввода команды. Командная строка автоматически войдет в диапазон:

:'<,'>

Вы можете ввести команду, например s / red / green / g, чтобы заменить каждый красный на зеленый во всех строках последнего визуального выделения. Команда будет выглядеть так:

:'<,'>s/red/green/g

Чтобы повторить команду Ex над ранее выбранным блоком, используйте: history. То есть нажмите: затем, затем отредактируйте предыдущую команду.


4
да, это заменяет красный на зеленый в выбранной области - очень полезно, но не то, о чем просила операция.
ErichBSchulz

@ErichBSchulz Фактически делает это для всех выбранных строк. Таким образом, даже если выбрана только часть строки, это будет сделано для всей строки.
Калли

1
Возможно, он не отвечает на вопрос OP, но это точно отвечает на мой поиск «vim search and replace with visual selection», где я хочу ограничить поиск и заменить только визуальным выбором, что вызывает этот вопрос
icc97

5

У меня это в моем vimrc:

function! GetVisual() range
    let reg_save = getreg('"')
    let regtype_save = getregtype('"')
    let cb_save = &clipboard
    set clipboard&
    normal! ""gvy
    let selection = getreg('"')
    call setreg('"', reg_save, regtype_save)
    let &clipboard = cb_save
    return selection
endfunction

vmap <leader>z :%s/<c-r>=GetVisual()<cr>/

Это захватит визуальное выделение и запустит с ним команду замены.

РЕДАКТИРОВАТЬ: я должен указать, что это не работает с многострочным визуальным выбором. Хотя GetVisual () не имеет проблем с его возвратом, я не уверен, как правильно поместить его в командную строку. Если у кого-нибудь есть советы, как я могу это сделать, прокомментируйте.


2

Я не думаю, что вы сможете сделать это из коробки. Но многим эта функция нравится, поэтому есть масса макросов и тому подобное (я сам добавил). Вот тот, который вы можете добавить, например; просто нажмите, *чтобы найти следующее совпадение по визуально выделенному тексту.


2

Другие ответы хороши, но в них не используются специальные символы. Ответ на @ Брайан Kennedy показывает способ , чтобы избежать , но это требует много кода. Например, в случае URL-адреса экранирование обязательно или поиск остановится на «:».

Как написано в vim.fandom.com/wiki/Search_for_visually_selected_text , вы можете использовать единственную строку для поиска и экранирования некоторых символов. Вы можете убежать от нужных персонажей, я решил убежать /\: :

vnoremap // y/\V<C-R>=escape(@",'/\:')<CR><CR>

С этой картой я должен нажать //в визуальном режиме, чтобы найти текущий выделенный текст во всем буфере.


1

Моя любимая короткая версия этого

vnoremap s / y: s / "/

Затем вы можете выделить выделение и просто нажать s /, чтобы запустить для него команду замены.


Не сработало для меня, воспринималось "буквально. <c-r>"хотя работал
Джош Бода

1

У меня нет представителя для комментариев, поэтому я добавляю еще один ответ ...

vnoremap <C-r> "0y<Esc>:%s/<C-r>0//g<left><left>

@dmd и @dotancohen: это сработало для меня без использования "h(явно используется 0, который в любом случае является последней позицией восстановления) и работает с putty ssh -> mint (lmde); не знаю про цент. Также использует комментарии @Niloct и @Nathan Friend для удаления подтверждения.


1

Пример 1. Цитировать выделение звездочками, держать курсор в начале выделения.

:%s,\%#\%V\_.*\%V/,**&**,c 

Пример 2. Соедините выделенный текст с помощью base64:

:%s!\%#\%V\_.*\%V!\=system("base64 -w 0",@")!c

Пояснение LHS:

\%# matches cursor 
\%V matches inside the selection only
\_. matches any character.
\_.* matches beginning to end of selection.

Пояснение RHS:

\=expr()  Replace match with result of expr() for each substitution.

0

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

Наведя курсор мыши на слово, нажмите *или, #чтобы выделить слово и перейти к следующему / предыдущему его местоположению (если вы не хотите менять местоположение в файле, нажмите противоположную клавишу, чтобы вернуться в это место. вы только что были).

Затем просто введите:

%s//<your-replacement-string>

Как упоминалось в ответе другого человека, если %sмежду косыми чертами появляется пустая запись, то используется слово, которое ранее искали. Нажимая *или #, вы ищете слово под курсором, что делает его последним искомым словом.

В конце концов, для этого достаточно шести или семи нажатий клавиш + длина заменяющего слова, и это не требует макроса или редактирования вашего .vimrc.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.