# Simultaneous find and replace

Is there a way to perform a simultaneous find and replace?

e.g.: I want to replace all `1` for `0` and simultaneously all `0` to `1`

``````[
[1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 0, 1],
[1, 1, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1],
[1, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 0],
]

``````

## 10 Answers

Yes, you can do that by using an expression. For this particular case, you can use Vim arithmetic and calculate `1-x`, which will turn 0 into 1 and 1 into 0.

``````:s/\d/\=1-submatch(0)/g
``````

For a more general replacement case, you can use a Dict to store the mapping of match to replacement string.

For example, to turn the digits into written numbers:

``````:let repl = {"0": "zero", "1": "one"}
:s/\d/\=repl[submatch(0)]/g
``````

See:

There's a bunch of excellent answers here already, but for the sake of completeness I feel like I should point out that, in most practical respects, if you concatenate multiple ex commands with the bar character `|`, they act like a single operation.

In particular, they will lead to a single item in each of the undo tree and changelist.

As such, the following acts like a simultaneous change of 1 to 0 and 0 to 1:

``````:%s/1/TEMP/g | %s/0/1/g | %s/TEMP/0/g
``````
• I like these kind of solutions; the other ones are more clever and arguably better, but this one is easier to remember and has lower cognitive load. Sometimes I spend more time getting the "clever" method to work than I save by just using the "dumb" method. Maybe I'm just not smart enough heh Apr 30 '20 at 18:15

In your specific use case, i think what you can do is this handy oneline:

``````%s/0\|1/\=!submatch(0)/g
``````

That basically inverts the match.

Sure:

``````%s/[01]/\="10"[submatch(0)]/g
``````

Matches either a `0` or `1` and replaces it with either

`"10"[0]` = `1`

or

`"10"[1]` = `0`

This answer is longer than others, it didn't take the specific data value advantage, it's a general solution to replace n different values with n different replacements:

``````let d={0:1,1:0} | %s/\v(0|1)/\=d[submatch(0)]/g | unlet d
``````

So if you want to change `Hello vim 8` to `Oh god 9` in a single replacement:

``````let d={'Hello':'Oh','vim':'god',8:9} | %s/\v(Hello|vim|8)/\=d[submatch(0)]/g | unlet d
``````

I'm actually surprised there is no native `tr` in vi/vim, but if your platform is UNIXy enough, there's an external command for just this:

``````:%!tr 01 10
``````

This is what I would personally use, but it may not be portable enough for you.

I'm quite certain I've already gave an answer to the general case either here on vi.SE, or on stackoverflow, but impossible to find the Q/A...

In that answer I provide the command `CycleSubstitute` that could be used in your case in the following way

``````:[range]CycleSubstitute/0/1
``````

I've packaged it here. And it's implemented in the following way:

``````:command! -bang -nargs=1 -range CycleSubstitute <line1>,<line2>call s:CycleSubstitute("<bang>", <f-args>)

function! s:CycleSubstitute(bang, repl_arg) range
let do_loop = a:bang != "!"
let sep = a:repl_arg[0]
let fields = split(a:repl_arg, sep)
let cleansed_fields = map(copy(fields), 'substitute(v:val, "\\\\[<>]", "", "g")')
" build the action to execute
let action = '\=s:DoCycleSubst('.do_loop.',' . string(cleansed_fields) . ', "^".submatch(0)."\$")'
" prepare the :substitute command
let args = [join(fields, '\|'), action ]
let cmd = a:firstline . ',' . a:lastline . 's'
\. sep . join(fields, '\|')
\. sep . action
\. sep . 'g'
" echom cmd
" and run it
exe cmd
endfunction

function! s:DoCycleSubst(do_loop, fields, what)
let idx = (match(a:fields, a:what) + 1) % len(a:fields)
return a:fields[idx]
endfunction
``````

Similar to @LucHermitte's answer, the SwapStrings plugin lets you do

``````:%SwapStrings 0 1
``````

My own PatternsOnText plugin provides (among many others) a `:SubstituteMultiple` command that can do swaps as a corner case of doing multiple substitutions atomically (that is, without introducing a temp replacement):

``````:%SubstituteMultiple /0/1/ /1/0/ g
``````

To add to the list of plugins allowing this, vim-abolish features the `Subvert` function which can be leveraged to achieve multiple replaces:

``````%Subvert/{1,0}/{0,1}/g
``````
``````:%s/\([01]\)/\=1-submatch(1)/g
``````

The following is taking place in the substitute command

• Search for 1 or 0, remember it as submatch 1 (between the first / and second /)
• Replace with the value by subtracting from 1 (between the second / and third /)
• 1 becomes 0 and 0 becomes 1

\= is interpreted as the beginning of a mathematical expression in the substituted section

• Welcome to Vi and Vim! Good answers usually provide an explanation alongside code in order to be instructive May 1 '20 at 1:29