vim regex replace multiple consecutive spaces with only one space
this will replace 2 or more spaces
s/ \{2,}/ /g
or you could add an extra space before the \+
to your version
s/ \+/ /g
This will do the trick:
%s![^ ]\zs \+! !g
Many substitutions can be done in Vim easier than with other regex dialects by using the \zs
and \ze
meta-sequences. What they do is to exclude part of the match from the final result, either the part before the sequence (\zs
, “s” for “start here”) or the part after (\ze
, “e” for “end here”). In this case, the pattern must match one non-space character first ([^ ]
) but the following \zs
says that the final match result (which is what will be replaced) starts after that character.
Since there is no way to have a non-space character in front of line-leading whitespace, it will be not be matched by the pattern, so the substitution will not replace it. Simple.
In the interests of pragmatism, I tend to just do it as a three-stage process:
:g/^ /s//XYZZYPARA/g
:g/ \+/s// /g
:g/^XYZZYPARA/s// /g
I don't doubt that there may be a better way (perhaps using macros or even a pure regex way) but I usually find this works when I'm in a hurry. Of course, if you have lines starting with XYZZYPARA
, you may want to adjust the string :-)
It's good enough to turn:
This is a new paragraph
spanning two lines.
And so is this but on one line.
into:
This is a new paragraph
spanning two lines.
And so is this but on one line.
Aside: If you're wondering why I use
:g
instead of:s
, that's just habit mostly.:g
can do everything:s
can and so much more. It's actually a way to execute an arbitrary command on selected lines. The command to execute happens to bes
in this case so there's no real difference but, if you want to become avi
power user, you should look into:g
at some point.
There are lots of good answers here (especially Aristotle's: \zs
and \ze
are well worth learning). Just for completeness, you can also do this with a negative look-behind assertion:
:%s/\(^ *\)\@<! \{2,}/ /g
This says "find 2 or more spaces (' \{2,}'
) that are NOT preceded by 'the start of the line followed by zero or more spaces'". If you prefer to reduce the number of backslashes, you can also do this:
:%s/\v(^ *)@<! {2,}/ /g
but it only saves you two characters! You could also use ' +'
instead of ' {2,}'
if you don't mind it doing a load of redundant changes (i.e. changing a single space to a single space).
You could also use the negative look-behind to just check for a single non-space character:
:%s/\S\@<!\s\+/ /g
which is much the same as (a slightly modified version of Aristotle's to treat spaces and tabs as the same in order to save a bit of typing):
:%s/\S\zs \+/ /g
See:
:help \zs
:help \ze
:help \@<!
:help zero-width
:help \v
and (read it all!):
:help pattern.txt
Answered; but though i'd toss my work flow in anyway.
%s/ / /g
@:@:@:@:@:@:@:@:@:@:@:@:(repeat till clean)
Fast and simple to remember. There are a far more elegant solutions above; but just my .02.