Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim: substitution in a range that is less than a line

Let's say I have the following line of code:

something:somethingElse:anotherThing:woahYetAnotherThing

And I want to replace each : with a ; except the first one, such that the line looks like this:

something:somethingElse;anotherThing;woahYetAnotherThing

Is there a way to do this with the :[range]s/[search]/[replace]/[options] command without using the c option to confirm each replace operation?

As far as I can tell, the smallest range that s acts on is a single line. If this is true, then what is the fastest way to do the above task?

like image 443
Will Avatar asked Nov 08 '12 22:11

Will


4 Answers

I'm fairly new to vim myself; I think you're right about range being lines-only (not 100% certain), but for this specific example you might try replacing all of the instances with a global flag, and then putting back the first one by omitting the global -- something like :s/:/;/g|s/;/:/.

Note: if the line contains a ; before the first : then this will not work.

like image 130
AlliedEnvy Avatar answered Sep 28 '22 20:09

AlliedEnvy


Here you go...

:%s/\(:.*\):/\1;/|&|&|&|&

This is a simple regex substitute that takes care of one single not-the-first :.

The & command repeats the last substitute.

The | syntax separates multiple commands on one line. So, each substitute is repeated as many times as there are |& things.

like image 35
DigitalRoss Avatar answered Sep 28 '22 20:09

DigitalRoss


Here is how you could use a single keystroke to do what you want (by mapping capital Q):

map Q :s/:/;/g\|:s/;/:<Enter>j

Every time you press Q the current line will be modified and the cursor will move to the next line.

In other words, you could just keep hitting Q multiple times to edit each successive line.

Explanation:

This will operate globally on the current line:

:s/:/;/g

This will switch the first semi-colon back to a colon:

:s/;/:

The answer by @AlliedEnvy combines these into one statement.

My map command assigns @AlliedEnvy's answer to the capital Q character.


Another approach (what I would probably do if I only had to do this once):

f:;r;;.

Then you can repeatedly press ;. until you reach the end of the line.

(Your choice to replace a semi-colon makes this somewhat comfusing)

Explanation:

  • f: - go to the first colon
  • ; - go to the next colon (repeat in-line search)
  • r; - replace the current character with a semi-colon
  • ; - repeat the last in-line search (again)
  • . - repeat the last command (replace current character with a semi-colon)

Long story short:

  • fx - moves to the next occurrence of x on the current line
  • ; repeats the last inline search
like image 33
jahroy Avatar answered Sep 28 '22 19:09

jahroy


While the other answers work well for this particular case, here's a more general solution:

Create a visual selection starting from the second element to the end of the line. Then, limit the substitution to the visual area by including \%V:

:'<,'>s/\%V:/;/g

Alternatively, you can use the vis.vim plugin

:'<,'>B s/:/;/g
like image 39
Ingo Karkat Avatar answered Sep 28 '22 20:09

Ingo Karkat