Ninth Prince has asked for the wisdom of the Perl Monks concerning the following question:

I have a progarm where I basically run two regex matches in a row (on the same document). It seems like my ability to match depends on the ordering of the matches. The code looks something like this:

if ($content =~ m%match (pattern)%g) { $firstVariable = $1 ; } #end if if ($content =~ m%match (pattern2)%g) { $secondVariable = $1 ; } #end if

If I put one of the ifs first, both match, but if I reverse the ordering of the ifs, only one matches (the one first in order).

What's going on? Do I need to "reset" the search back to the beginning of the $content string? If so, how to do? Thanks.

Replies are listed 'Best First'.
Re: Matching regular expressions question
by BrowserUk (Patriarch) on May 26, 2008 at 23:51 UTC

    If you use the //g modifier in a scalar context, then the next match attempt, from the same regex or a another, will continue from where the last match occured. This is used to good effect when //g is used in conjunction with a while loop to process all the possible matches one at a time:

    while( $string =~ m/$re/g ) { ## process all matches one at a time }

    By calling your first regex with //g and in an if condition (scalar context), you are asking for the first match for that regex, and then asking for the next regex to continue the search from that position. But, as this is an if statement you're never going to loop back to process any second (or subsequent) match to the first regex.

    In summary, drop the //g modifiers and you'll probably get the results you are looking for.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Great, thanks! I understand.
Re: Matching regular expressions question
by pc88mxer (Vicar) on May 26, 2008 at 23:43 UTC
    What's going on? Do I need to "reset" the search back to the beginning of the $content string?
    Yes, you do. The conventional way to use the /g modifier is with a while loop:
    while ($text =~ m/.../g) { ... }
    When the while loop terminates the match position associated with $text is at the end, so the next time you match it with a /g modifier the search will begin from the start of the start of the string.

    It appears you can reset the last match position by either:

    • modifying the variable (even $text .= '' works)
    • explicitly setting pos(...), i.e. pos($text) = 0
    Here is some test code:
    my $text = "aaa"; while ($text =~ m/a/g) { last } # only executes once pos($text) = 0; # $text .= ''; # another way to do it print "matched\n" if ($text =~ m/aaa/g)
      How?
Re: Matching regular expressions question
by ikegami (Patriarch) on May 27, 2008 at 00:48 UTC
    An illustration that should help:
    >perl -le"for (1..2) { 'abc' =~ /(.)/g; print $1 }" a b >perl -le"for (1..2) { 'abc' =~ /(.)/; print $1 }" a a