Vim regex replaces multiple consecutive spaces with just one space

I often work with text files that have a variable number of spaces as word separators (word processors such as Word do this to distribute a fair amount of spaces due to the different size of letters in certain fonts, and they put this annoying space variable even when saving as plain text).

I would like to automate the process of replacing these sequences of spaces having a variable length with single spaces. I suspect that the regular expression can do this, but there are also spaces at the beginning of the paragraphs (usually four of them, but not always) that I would like to leave unchanged, so basically my regular expression should also not touch leading white spaces, and this adds to the complexity.

I am using vim, so a regex in the regex vim dialog would be very useful for me if that is doable.

My current move is as follows:

:%s/ \+/ /g 

but it does not work correctly.

I am also thinking of writing a vim script that could parse text strings one by one, process each char string to char and skip spaces after the first, but I have the feeling of being excessive.

+51
vim regex
Oct 05 2018-10-10T00:
source share
7 answers

In the interest of pragmatism, I usually do this as a three-step process:

 :g/^ /s//XYZZYPARA/g :g/ \+/s// /g :g/^XYZZYPARA/s// /g 

I have no doubt that there may be a better way (perhaps using macros or even pure regex), but I usually find this to work when I'm in a hurry. Of course, if you have lines starting with XYZZYPARA , you can customize the line XYZZYPARA

Good enough to rotate:

  This is a new paragraph spanning two lines. And so is this but on one line. 

at

  This is a new paragraph spanning two lines. And so is this but on one line. 



Also: if you are wondering why I use :g instead of :s , this is just a habit basically. :g can do everything :s can do more. This is actually a way to execute an arbitrary command on selected lines. The command to execute in this case will be s , so there is no real difference, but if you want to become a strong vi user, at some point you should look at :g .

+30
Oct 05 '10 at 2:56
source share

it will replace 2 or more spaces

 s/ \{2,}/ /g 

or you can add extra space before \+ to your version

 s/ \+/ /g 
+79
05 Oct '10 at 2:51
source share

This will do the trick:

 %s![^ ]\zs \+! !g 

Many permutations can be made easier in Vim than with other regex dialects 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 first match one non-spatial character ( [^ ] ), but the next \zs says that after this character the final result of the match begins (which will be replaced).

Since there is no way to have a non-spatial character in front of a leafy space, it will not match the pattern, so replacement will not replace it. Plain.

+55
05 Oct 2018-10-10T00:
source share

There are many good answers here (especially Aristotle: \zs and \ze worth exploring). Just for completeness, you can also do this with a negative statement:

 :%s/\(^ *\)\@<! \{2,}/ /g 

This says β€œfind 2 or more spaces ( ' \{2,}' ) that are NOT preceded by aβ€œ beginning of line followed by zero or more spaces. ”If you want to reduce the number of backslashes, you can also do this:

 :%s/\v(^ *)@<! {2,}/ /g 

but it only saves you from two characters! You can also use ' +' instead of ' {2,}' if you do not mind that it carries out the load of redundant changes (i.e., exchanged one space for one place).

You can also use negative appearance to just check one non-spatial character:

 :%s/\S\@<!\s\+/ /g 

which is almost the same as (slightly modified version of Aristotle for handling spaces and tabs as the same to save a bit of input):

 :%s/\S\zs \+/ /g 

Cm:

 :help \zs :help \ze :help \@<! :help zero-width :help \v 

and (read everything!):

 :help pattern.txt 
+5
05 Oct 2018-10-10 at
source share

It works?

 %s/\([^ ]\) */\1 /g 
+1
05 Oct
source share

I like this version - it looks like a promising version of Aristotle Pagaltzis, but it's easier for me to understand it. (Maybe just my ignorance with \ zs)

 s/\([^ ]\) \+/\1 /g 

or for all spaces

 s/\(\S\)\s\+/\1 /g 

I read it as "replacing all occurrences of something other than a space, followed by several spaces with something and one space."

+1
Oct 05 '10 at 4:13
source share

Answered; but despite the fact that I would give up my workflow anyway.

 %s/ / /g @:@:@:@:@:@:@:@:@:@:@:@:(repeat till clean) 

Quick and easy to remember. There are more elegant solutions above; but only my .02.

+1
Oct 05 2018-10-10
source share



All Articles