vicky.dev
vicky.dev

Reputation: 115

vim regex for replacing spaces within quotes

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!

Upvotes: 8

Views: 3591

Answers (4)

Alan G&#243;mez
Alan G&#243;mez

Reputation: 378

I think that this regex could be usefull:

:%s/\(^.\{-}"\)\| /_\1/g | %s/^_//g

From:

ERR_OUT_OF_MEM, "ERR OUT OF MEM"

ERR_SOMETHING_BAD, "ERR SOMETHING BAD"

to:

ERR_OUT_OF_MEM, "ERR_OUT_OF_MEM"

ERR_SOMETHING_BAD, "ERR_SOMETHING_BAD"

Upvotes: 0

Ingo Karkat
Ingo Karkat

Reputation: 172768

My PatternsOnText plugin provides a :SubstituteInSearch command. With it, you first search for the quoted strings, then perform a :substitute only within the matches:

/".\{-}"
:SubstituteInSearch/_/ /g

Upvotes: 0

Luc Hermitte
Luc Hermitte

Reputation: 32986

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

Upvotes: 10

John Hyland
John Hyland

Reputation: 6872

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.

Upvotes: 6

Related Questions