0

I'd like to swap two words using capture groups in Vim using only one line of regex, but I cannot find a solution to this for example

word1
word2

expecting:
word2
word1

get:
word1
word2

I've also tried s/(word1)(word2)/\2\1/g but they don't swap their position or even replace

Is there any way I can achieve this?

  • `vi` should support [`\_` to match whitespace including newlines](https://vi.stackexchange.com/q/13603), but it doesn't want to work on my `vim`. Perhaps try [vi.se] for a better answer. – Ken Y-N Feb 15 '22 at 07:41

3 Answers3

4

You are not matching the newline in between, and the newline is also not present in the replacement.

For the capture groups you can escape the parenthesis:

\(word1\)\n\(word2\)/\2\r\1/

Output

word2
word1

If you want to replace all occurrences and not have to escape the parenthesis you can use the very magic mode using \v and use %s

%s/\v(word1)\n(word2)/\2\r\1/g

If the word can be spread, you can match any character non greedy in between and also use a capture group for that in the replacement.

%s/\v(word1)(\_.{-})(word2)/\3\2\1/g

See this page for extensive documentation.

The fourth bird
  • 154,723
  • 16
  • 55
  • 70
  • @CarySwoveland No I read on this page that it should be a `\r` https://stackoverflow.com/questions/71417/why-is-r-a-newline-for-vim – The fourth bird Feb 15 '22 at 07:47
  • thanks for the answer, however if my words are spread in different places, this method will not work – Darren Wang Feb 15 '22 at 07:53
  • @DarrenWang Then you can use 3 capture groups and match as least as possible chars between the matches and also capture that in a group for the replacement `%s/\(word1\)\(\_.\{-}\)\(word2\)/\3\2\1/g` – The fourth bird Feb 15 '22 at 08:01
0

I am all for designing under hard constraints but pragmatism has value, too. What good is it to wait for someone else to write you a super fancy one-liner when you can write three super simple commands on the spot?

:%s/word1/§§§§/g
:%s/word2/word1/g
:%s/§§§§/word2/g

If you really dig the mystique of one-liners:

:%s/word1/§§§§/g|%s/word2/word1/g|%s/§§§§/word2/g
romainl
  • 186,200
  • 21
  • 280
  • 313
0

I doubt this exactly what you looking for, however Tim Pope's Abolish provides the :Subvert/:S command which can make swapping easy

:%S/{foo,bar}/{bar,foo}/gw

This will swap the following:

foo -> bar
bar -> foo

:Subvert takes similar flags to :s. I am using w for word-wise and g for global

Peter Rincker
  • 43,539
  • 9
  • 74
  • 101