views:

64

answers:

3

For the sake of simplicity, let's say that we have input strings with this format:

*text1*|*text2*

so, I want to leave text1 alone, and remove all spaces in text2

This could be easy if we didn't have text1, a simple search and replace like this one would do:

%s/\s//g

but in this context I don't know what to do.

I tried with something like:

%s/\(.*|\S*\).\(.*\)/\1\2/g

which works, but removing only the first character, I mean, this should be run on the same line one time for each offending space.

So, a preferred restriction, is to solve this with only one search and replace. And, although I used vim syntax, use the regex flavor you're most comfortable with to answer, I mean, maybe you need some functionality only offered by Perl.

Edit: My solution for vim:

%s:\(|.*\)\@<=\s::g
+3  A: 

One way, in perl:

s/(^.*\||(?=\s))\s*/$1/g

Certainly much greater efficiency is possible if you allow more than just one search and replace.

ysth
I'm currently reading this answer to a similar question that I found only after asking mine. http://stackoverflow.com/questions/608319/regex-replace-but-only-between-two-patternsThe accepted response uses lookaround to, so maybe yours is similar. I haven't grokked lookaround yet, so I'll try to understand your solution and see if it works.
Doppelganger
@Doppelganger: The lookaround isn't actually necessary in mine; `s/(^.*\||)\s*/$1/g` should work just as well. I was thinking the lookforward would make it some faster, but don't know if that's true.
ysth
I found my solution with lookaround, but I'm still trying to understand yours. I don't get this atom (^.*\||), i get it as anything from beginning of line until a pipe, but I don't understand what the second pipe is for.
Doppelganger
The second pipe means "or nothing". After the first time, the capturing group matches the empty string before each character. If the `\s*` matches any spaces, they get discarded because they're not included in the group. Success with regexes is all about thinking outside the box. ;)
Alan Moore
+3  A: 

So you have a string with one pipe (|) in it, and you want to replace only those spaces that don't precede the pipe?

s/\s+(?![^|]*\|)//g
Alan Moore
Better than mine. Or `s/\s+(?!.*?\|)//gs`
ysth
A: 

you might try embedding perl code in regex (using (?{...}) syntax), which is however rather an experimental feature and might not work or even be available in your scenario.

this

s/(.*?\|)(.*)(?{ $x = $2; $x =~ s:\s::g })/$1$x/

should theoretically work, but i got "Out of memory!" failure, which can be fixed replacing '\s' with a space:

s/(.*?\|)(.*)(?{ $x = $2; $x =~ s: ::g })/$1$x/
mykhal
If you are doing multiple substitutions, might as well do `s/(\|.*)/(my$x=$1)=~s!\s!!g;$x/se`; no `(?{...})` needed.
ysth