Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi I have a question about searching and replacing a line globally.
#!/usr/bin/perl -w my $default_from_domain = 'www.domain.com'; my $unsub = 'un-foo@foo.com un-foo@foo.com'; print $unsub, "\n"; $unsub =~ s/(un-.*)\@(.*)/$1\@$default_from_domain/g ; print $unsub;
returns:

un-foo@foo.com un-foo@foo.com
un-foo@foo.com un-foo@www.domain.com

i want it to return

un-foo@foo.com un-foo@foo.com
un-foo@www.domain.com un-foo@www.domain.com

Replies are listed 'Best First'.
Re: regex search and replace globally
by Enlil (Parson) on Apr 30, 2003 at 01:03 UTC
    Death to Dot Star is a good read.

    your regex is capturing to much to fast. This is better:

    #!/usr/bin/perl -w use strict; use warnings; my $default_from_domain = 'www.domain.com'; my $unsub = 'un-foo@foo.com un-foo@foo.com'; print $unsub, "\n"; $unsub =~ s/(un-[^\@]+)\@[^ ]+/$1\@$default_from_domain/g ; print $unsub;
    update:
    Assuming the optimizer did not exist your regex would capture as follows (not sure how the optimizer optimizes so I am going to pretend it is not there): the (un-.*) would capture from the first place it sees un- in your string and then the .* makes it capture from this point on. It will then try to match the next thing in your regex which in your case is \@ it will thus backtrack until it finds one. At this point you have "un-foo@foo.com un-foo@" matching. The little engine that could then moves on and tries to match the next thing. Which is again .* which will of course capture the rest of the string.

    So far you have the following then: $1 contains "un-foo@foo.com un-foo" and $2 contains "foo.com". Anyhow since it captures the whole string right of the bat it will not find another match.

    -enlil

      not sure how the optimizer optimizes so I am going to pretend it is not there

      In general, every regexp should match exactly the same with the optimiser as without it, so this is usually the right thing to do.

      If you want to delve more deeply ...

      That's about it. The two functions that deal with all this - one to find the optimisation information, and one to use it - are without doubt the two pieces of code most likely to cause insanity and/or sleepless nights in 90% of all respondents that didn't run away when we asked.

      Update 2006/04/06: a paragraph was truncated, I finished it off.

      Hugo

      How would i change the regex to handle something like
      my $unsub = 'un-foo@foo.com un-foo@foo.com'; my $unsub = 'un-foo@foo.com \'un-foo@foo.com\''; my $unsub = 'un-foo@foo.com "un-foo@foo.com"';
Re: regex search and replace globally
by The Mad Hatter (Priest) on Apr 30, 2003 at 00:59 UTC
    The .* is acting too greedy (and matching up to the second @).