Let's say we have a text, and I enter visual mode and select some text. How do I quickly do a search for the highlighted text and replace it with something else?
-
3This question demonstrates one of the most frustrating shortcomings of vim. This job could be done in a couple of seconds in any graphical editor. But as all the answers provided show we have to jump through many hoops before we can get vim to do the same.user9224371– user92243712021-09-20 14:11:52 +00:00Commented Sep 20, 2021 at 14:11
-
@user9224371 this is only half-true at least. If you come into not configured (n)vim as newbie -> it's definitely as you said. There is other part though. For advanced vim user muscle memory is built up in way they can do this faster than most folks find the search&replace function in GUI editors and/or (n)vim can be configured to work similarly to any other editor in this regards eg. use <C-h> to replace highlighted text if you wish.GreenMarty– GreenMarty2024-08-27 06:50:01 +00:00Commented Aug 27, 2024 at 6:50
-
I use gVim. Add the windows remaps for Ctrl-C, Ctrl-V, etc. After highlighting, do (this might be slightly hard to understand, but): Ctrl-C,:%s#,Ctrl-V,#<replacement text#,<enter>AlastairG– AlastairG2024-09-23 12:49:44 +00:00Commented Sep 23, 2024 at 12:49
-
That basically copies the highlighted text to the clipboard, and then does a search and replace, using paste to dump the text to be replaced without needing to type it.AlastairG– AlastairG2024-09-23 12:50:55 +00:00Commented Sep 23, 2024 at 12:50
-
Notepad++ is in such cases the better optionKustekjé Meklootn– Kustekjé Meklootn2025-08-25 21:06:21 +00:00Commented Aug 25 at 21:06
15 Answers
Try execute the following or put in into your .vimrc
vnoremap <C-r> "hy:%s/<C-r>h//gc<left><left><left>
By pressing ctrl+r in visual mode, you will be prompted to enter text to replace with. Press enter and then confirm each change you agree with y or decline with n.
This command will override your register h so you can choose other one (by changing h in the command above to another lower case letter) that you don't use.
14 Comments
c in gc, replace is done at once in the whole buffer. If you made a mistake and want to revert it, just type u in command mode. I like this approach better than confirming each one of the replacements (that happens with the c modifier).vmap * y:let @/ = @"<CR> selected is highlighted.<left><left><left>?c from gc, you'll also have to remove one of the <left>'s from the end of the line.This one works also (at least for selections in a single line / selections that don't contain any special characters)
- select the text in visual mode
- yank the text with
y :s/<C-r>0/
0 is the yank register.
<C-r> is Ctrl+r
As other people mentioned, there are faster ways to do this, but if you've just started learning Vim (like me), this is one of the 'generic' ways.
//edit: I've just realized that the 'register' approach will fail if there are characters like tabs or newlines or / characters in the selection (I'd have to manually process those characters somehow in order for the :s command to work):

3 Comments
:%s*<C-r>0*/Users/very/long/path/here/*gcThis quick and simple mapping search for visually highlighted text (without over-writing the h register) and without using the terminal dependant + register:
" search for visually hightlighted text
vnoremap <c-f> y<ESC>/<c-r>"<CR>
If you dont like the ctrl-f change it to your preference
Once the text is highlighted you can always do a substitution simply by typing:
%s//<your-replacement-string>
... because a blank search on the s command uses the last searched for string.
2 Comments
control+f always selects the very next character as well as what I visually selected. Any ideas?%s//<your-replacement-string> doesn't seem to work for highlighting something like /tmp/file. it just becomes <your-replacement-string>/tmp/fileFrom Vim 7.4, you can use the gn motion which selects regions of text that match the current search pattern.
After using cgn to change the text in currently selected match (or dgn to delete), in normal mode, you can use . to repeat the command and operate on the next match.
There's an episode of Vimcast showing this feature.
3 Comments
gn and then hit cgn, it will jump into insert mode without waiting for gn. Hitting n and then . applies this manipulation to the following matches.The accepted answer works great unless you have special characters in your visual selection. I hacked together two scripts (Jeremy Cantrell's posted here & Peter Odding's) to make a command that will allow you to visual select a string that you want to find even if it has special regex characters in it.
" 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 - https://stackoverflow.com/questions/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>/
I've included this in my vimrc if that's more useful to anyone.
2 Comments
vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left> (which just replaces all in file)vmap needed here? Anyway, thanks, this is a gem and looks like it is solving my vi.stackexchange.com/questions/41421/… Also, using ctrl+R is clever. I hadn't considered visual mode is in a different key binding space compared to normal modeI was hoping there was a built in way in Vim to replace a word, without having to retype the word out in the first place. There is, although it will only work for text up to a word boundary character.
Once you've moused over the word, press * or # to highlight the word and jump to the next/previous location of it (if you don't want to change locations in the file, then press the opposite key to go back to the location you were just at).
Then just type:
%s//<your-replacement-string>
As mentioned in another person's answer, if %s receives a blank entry between the slashes, then it uses the previously searched for word. By pressing * or #, you're searching for the word under the cursor which makes it the most recently searched word.
In the end it's only six or seven keystrokes + length of replacement word to perform this and it requires no macro or editing of your .vimrc.
Comments
Mykola Golubyev, Thanks for the tip! Following uses the "+" register which (depending on your terminal) already contains the highlighted text, saving from using the "h" register.
vnoremap <C-r> <Esc>:%s/<C-r>+//gc<left><left><left>
3 Comments
I have this in my 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>/
This will grab the visual selection and start a substitution command with it.
EDIT: I should point out that this does not work with multiline visual selections. While GetVisual() doesn't have a problem returning it, I'm not sure how to properly put it into the command line. If anyone has any tips on how I might do this, please comment.
Comments
Other answers are good but they do not escape special characters. The answer of @brian kennedy shows a method to escape but it requires much code. In case of an URL for instance, escaping is mandatory or the search will stop on “:”.
As written in vim.fandom.com/wiki/Search_for_visually_selected_text, you can do a oneliner to search and escape some characters. You can escape the characters you want, I chose to escape /\: :
vnoremap // y/\V<C-R>=escape(@",'/\:')<CR><CR>
With this map, I must press // in visual mode to search the currently selected text on the whole buffer.
Comments
If you are using Neovim, here is a cleaner Lua implementation of bryan kennedy's answer:
-- get contents of visual selection
-- handle unpack deprecation
table.unpack = table.unpack or unpack
function get_visual()
local _, ls, cs = table.unpack(vim.fn.getpos('v'))
local _, le, ce = table.unpack(vim.fn.getpos('.'))
return vim.api.nvim_buf_get_text(0, ls-1, cs-1, le-1, ce, {})
end
vim.keymap.set("v", "<C-r>", function()
local pattern = table.concat(get_visual())
-- escape regex and line endings
pattern = vim.fn.substitute(vim.fn.escape(pattern, "^$.*\\/~[]"),'\n', '\\n', 'g')
-- send parsed substitution command to command line
vim.api.nvim_input("<Esc>:%s/" .. pattern .. "//<Left>")
end)
Comments
I don't think you can do this out of the box. But lots of people like this feature, so there's tons of macros and such (I've added it myself). Here is one you can add, for example; just press * to search for the next match on the visually selected text.
Comments
Here is a variation on Mykola's answer. I like making substitutions starting from the current line to the end of the text, then from the beginning to the current line (essentially the loop starts from the current line instead of the beginning).
vnoremap <C-r> "hy:.,$s/<C-r>h//gc \|1,.&& <left><left><left><left><left><left><left><left><left><left><left>
First, the substitution is made from the current line to the end of the text .,$, then it is repeated from the beginning to the current line \|1,.&&. The 11 <left> put the cursor in the right place.
Comments
My favorite short version of this is
vnoremap s/ y:s/"/
Then you can highlight a selection and just hit s/ to start a substitution command for it.
1 Comment
" as a literal. <c-r>" worked thoughI don't have the rep to comment, so I'm adding yet another answer...
vnoremap <C-r> "0y<Esc>:%s/<C-r>0//g<left><left>
@dmd and @dotancohen: this worked for me without using up "h (explicitly uses 0, which is the last yank position anyway) and works with putty ssh -> mint (lmde); don't know about cent. Also uses @Niloct and @Nathan Friend comments to remove confirmation.
Comments
Example 1. Quote selection with stars, keep cursor at start of selection.
:%s,\%#\%V\_.*\%V/,**&**,c
Example 2. Pipe selected text with base64:
:%s!\%#\%V\_.*\%V!\=system("base64 -w 0",@")!c
Explanation LHS:
\%# matches cursor
\%V matches inside the selection only
\_. matches any character.
\_.* matches beginning to end of selection.
Explanation RHS:
\=expr() Replace match with result of expr() for each substitution.