Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the easiest way to swap occurrences of two strings in Vim?

Tags:

vim

vi

scripting

What is the easiest way to replace all occurrences of string_a with string_b while at the same time changing anything that was already string_b into string_a? My current method is as follows:

:s/string_a/string_c/g   :s/string_b/string_a/g   :s/string_c/string_b/g   

Although this works, it requires extra typing and seems inefficient. Does anybody know of a better way to do this?

like image 625
btw Avatar asked Aug 26 '10 19:08

btw


People also ask

How to replace all occurrences of a string in Vim?

Change and repeat Search for text using / or for a word using * . In normal mode, type cgn (change the next search hit) then immediately type the replacement. Press Esc to finish. From normal mode, search for the next occurrence that you want to replace ( n ) and press . to repeat the last change.

How to change all occurrences of a word in vi?

The % is a shortcut that tells vi to search all lines of the file for search_string and change it to replacement_string . The global ( g ) flag at the end of the command tells vi to continue searching for other occurrences of search_string . To confirm each replacement, add the confirm ( c ) flag after the global flag.

How to replace a text in Vim?

Basic Find and Replace In Vim, you can find and replace text using the :substitute ( :s ) command. To run commands in Vim, you must be in normal mode, the default mode when starting the editor. To go back to normal mode from any other mode, just press the 'Esc' key.


1 Answers

I'd do it like this:

:%s/\v(foo|bar)/\={'foo':'bar','bar':'foo'}[submatch(0)]/g 

But that's too much typing, so I'd do this:

function! Mirror(dict)     for [key, value] in items(a:dict)         let a:dict[value] = key     endfor     return a:dict endfunction  function! S(number)     return submatch(a:number) endfunction  :%s/\v(foo|bar)/\=Mirror({'foo':'bar'})[S(0)]/g 

But that still requires typing foo and bar twice, so I'd do something like this:

function! SwapWords(dict, ...)     let words = keys(a:dict) + values(a:dict)     let words = map(words, 'escape(v:val, "|")')     if(a:0 == 1)         let delimiter = a:1     else         let delimiter = '/'     endif     let pattern = '\v(' . join(words, '|') . ')'     exe '%s' . delimiter . pattern . delimiter         \ . '\=' . string(Mirror(a:dict)) . '[S(0)]'         \ . delimiter . 'g' endfunction  :call SwapWords({'foo':'bar'}) 

If one of your words contains a /, you have to pass in a delimiter which you know none of your words contains, .e.g

:call SwapWords({'foo/bar':'foo/baz'}, '@') 

This also has the benefit of being able to swap multiple pairs of words at once.

:call SwapWords({'foo':'bar', 'baz':'quux'}) 
like image 81
Brian Carper Avatar answered Sep 19 '22 06:09

Brian Carper