# 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],
]

``````

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:

• I love the elegance of the first solution. And the dict mapping in your second solution is a handy technique to know! Thanks!
– Aman
Commented Jul 25, 2022 at 2:03

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 Commented Apr 30, 2020 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.

• there is `:h tr()` Commented Apr 30, 2020 at 20:24
• And from the function, we can define a command: See stackoverflow.com/a/25665554/15934 Commented Apr 30, 2020 at 22:37

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 Commented May 1, 2020 at 1:29