tags:

views:

125

answers:

2

I have text in the follwing format:

ERR_OUT_OF_MEM, "ERR OUT OF MEM"
ERR_SOMETHING_BAD, "ERR SOMETHING BAD"

I want to replace all spaces in the text which are within quotes with underscores:

 ERR_OUT_OF_MEM, "ERR_OUT_OF_MEM"
 ERR_SOMETHING_BAD, "ERR_SOMETHING_BAD"

The best regex I could come up with is:

\("\w\+\)\@<= 

(there's a space at the end of that)

but this only finds the first space in each quoted string, and I would need to repeat this multiple times to get the desired effect.

Any way to do it in one shot?

Thanks!

+2  A: 

There is certainly a 0-length pattern that works in one pass, but as I never have much success using them, I prefer this kind of approach:

:%s/\%("[^"]*"\)*\("[^"]*"\)/\=substitute(submatch(1), ' ', '_', 'g')/g

Note: double-quotes are kept grouped 2 by 2 in order to not transform

foo bar "foo bar" "foo barr"

into

foo bar "foo_bar"_"foo_barr"

EDIT: as rampion pointed out, the following is more than enough:

%s/"[^"]*"/\=substitute(submatch(0), ' ', '_', 'g')/g
Luc Hermitte
Why not just use the `/"[^"]*"/` pattern? I don't get what skipping the initial pairs of quotes buys you (with `\%("[^"]*"\)*`)
rampion
Good point.I was persuaded that the search would start again not after the closing quote, but after the opening one. I correct the regex. Thanks.
Luc Hermitte
+5  A: 

This isn't a general-purpose solution, since it will match any space that appears anywhere after a double quote on a line, but it should work for strings in the format you've specified:

s/\v(\".*)@<= /_/g

I've used the \v (verymagic) token because I think it makes the regex a little more readable, and I included the whole substitution command, since the 'g' at the end is important.

For those following along at home, this regex first sets 'verymagic' mode with \v. Then it defines the token (\".*) which roughly means "a double quote and then anything else" and uses the lookbehind assertion @<= to say "only match things following that last token" - in other words, only match things that come somewhere after a double quote. Finally, there's a space, which is what actually gets matched, and the substitution term is an underscore, which is what we want to replace it with, and the g says "substitute all matching terms" so we don't just get the first match found.

John Hyland
This works, but it also replaces spaces that I have at the end of the line.
Ah. Yes, if you have trailing spaces you'll need a more complex approach. Luc's, above, should do it.
John Hyland