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

Dear Monks,
In structure like:
foreach(...) { my $re=qr/...$xxx..../o; @a = grep { /$re/ } @b ..... }
will $re be precompiled and therefore not changed only within one loop iteration and on the next one be recompiled again since $re is declared inside loop?

Replies are listed 'Best First'.
Re: Precompiling qr/.../o question
by leocharre (Priest) on Apr 02, 2008 at 13:50 UTC

    Good question.

    I think what the responses suggest, is that when you use qr//, it *is* compiled.. What I don't see a clear answer to is if although it is asked for multiple times, does the regex compiler do it one time only before runtime.

    I would imagine the answer is no, if your loop happens at runtime (not in a package setup event).

    Personally I tend to declare things like that outside the loop, since this will not change per iteration. Depending on what you're doing, this makes little difference. How many iterations are we considering? A thousand? A billion? WHy not just be safe and declare your qr// elsewhere???

Re: Precompiling qr/.../o question
by jwkrahn (Abbot) on Apr 02, 2008 at 13:27 UTC

    Yes, that is correct.   update: Because of the /o option the value of $xxx in the compiled regexp does not change.    See also What is '/o' really for?

Re: Precompiling qr/.../o question
by ikegami (Patriarch) on Apr 02, 2008 at 19:35 UTC

    The purpose of the o modifier was to speed up dynamically built regexps. The downside is that it creates hard to find bugs since any change to the regexp gets ignored. qr// was introduced as an alternative to the o modifier. There isn't any reason to use the o modifier any more.

    If all you want to do is avoid having $re compiled for every @b element, you don't need the o modifier:

    my $re=qr/...$xxx..../; @a = grep { /$re/ } @b

    There are checks in place to avoid recompiling a regexp is the interpolated variables haven't changed, so the following also does what you want:

    @a = grep { /...$xxx.../ } @b

    If you want the o behaviour:

    my $re; ... { $re ||= qr/.../; ... }

    If you want a cache:

    my %re_cache; ... { my $re = $re_cache{$key} ||= qr/.../; ... }

      Just to add a bit, a common performance pitfall is

      @regexps = qw( foo bar baz ); @strings = qw( abc def ghi ); for $string (@strings) { for $regexp (@regexps) { $string =~ /$regexp/ } }

      Each regexp is compiled for each element in @strings.

      >perl -Mre=debug -e"@regexps = qw( foo bar baz ); @strings = qw( abc d +ef ghi ); for $string (@strings) { for $regexp (@regexps) { $string = +~ /$regexp/ } }" 2>&1 | find "Compiling" Compiling REx `foo' Compiling REx `bar' Compiling REx `baz' Compiling REx `foo' Compiling REx `bar' Compiling REx `baz' Compiling REx `foo' Compiling REx `bar' Compiling REx `baz'

      Solution 1: Put the regexp loop on the outside:

      @regexps = qw( foo bar baz ); @strings = qw( abc def ghi ); for $regexp (@regexps) { # All I did was reverse for $string (@strings) { # these two lines. $string =~ /$regexp/ } }
      >perl -Mre=debug -e"@regexps = qw( foo bar baz ); @strings = qw( abc d +ef ghi ); for $regexp (@regexps) { for $string (@strings) { $string = +~ /$regexp/ } }" 2>&1 | find "Compiling" Compiling REx `foo' Compiling REx `bar' Compiling REx `baz'

      Solution 2: Precompile the regexps:

      @regexps = map qr/$_/, qw( foo bar baz ); # All I did was add the qr +//. @strings = qw( abc def ghi ); for $string (@strings) { for $regexp (@regexps) { $string =~ /$regexp/ } }
      >perl -Mre=debug -e"@regexps = map qr/$_/, qw( foo bar baz ); @strings + = qw( abc def ghi ); for $string (@strings) { for $regexp (@regexps) + { $string =~ /$regexp/ } }" 2>&1 | find "Compiling" Compiling REx `foo' Compiling REx `bar' Compiling REx `baz'
Re: Precompiling qr/.../o question
by hardburn (Abbot) on Apr 02, 2008 at 13:36 UTC

    The /o option is for use on the actual match or substitution. It's redundant on qr//. Actually, now that we have qr//, there's almost never a need to use /o, since /o can lead to confusing results in some cases.


    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      Are you sure?

      for ( 1 .. 5 ) { $foo = qr/$_/o; print "Match!\n" if '1' =~ m/$foo/; }

      and

      for ( 1 .. 5 ) { $foo = qr/$_/; print "Match!\n" if '1' =~ m/$foo/; }

      print entirely different outputs on perl 5.8.8 for me.

      Further, the reference in perlop for qr lists this usage:

      qr/STRING/msixpo

      The 'o' is listed as meaning "Compile pattern only once.".

      perlop does go on to say that if the compiled regex is embedded in a larger pattern that 'o', unlike the other options, will not propagate out to the other parts of the regex.

        Sure, it technically works (probably because /o gets dragged along into qr// like any other regex option list), but it's still redundant and confusing.

        The problem with /o is when you start with something harmless like this:

        for (1 .. 5) { print "Match!\n" if $some_string =~ /very long regex/o; }

        Then later you realize you need to add a loop variable to the regex:

        for (1 .. 5) { print "Match!\n" if $some_string =~ /very long regex $_ more regex/o; }

        Which results in the regex checking against '1' instead of the current loop var. This is almost never what you want, and has caused new and experienced programmers alike to waste many hours of debugging. That's why qr// was invented to Do the Right Thing.


        "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

        In your two additional examples (where you put $_ into the regex's) you are defeating the purpose of the 'compiled' regex. The compile option, I thought, was specifically for cases where the regex itself does *not* change.

        I thought the advantage of using the qr() construct was so that the compiler would look at the regex and do the right thing...i.e., compile the regex once if it does not change, otherwise recompile every usage when it *does* change. I'm not sure what the compiler does when you tell it to compile a regex (using the /o option specifier) that is not essentially static...in fact, I vaguely recall reading that it results in unpredictable regex compiler behavior. Is that the cause of the ...different behavior... that is reported in this thread? My recollection of the compiler behavior may just be a bad memory...since I usually work hard to ensure that the regex is really static and can safely expect to compile it only onc.

        I don't consider myself to be more than a novice with regex's...I'm gaining more and more experience with them and starting to drift towards that dangerous mental construct of seeing every problem as a regex waiting to birth itself. So all of the other good advice and commentary is from much more accomplished and knowledgable monks.

        ack Albuquerque, NM
Re: Precompiling qr/.../o question
by zentara (Cardinal) on Apr 02, 2008 at 17:28 UTC
    See using an array in a regex and Usage of grep on a file

    Also look at the explanation in the following snippet, from previous posts

    #!/usr/bin/perl #The difference between qr// and the /o modifier as I understand it is + #that with /o you can never change the pattern, whereas with qr// you #can compile the pattern to be used as part of a larger regex. @regexes = (); for $pattern (@patterns) { push @regexes, qr/$pattern/; } for $item (@data) { for $re (@regexes) { if ($item =~ /$re/) { print "Matches!\n"; } } } #/o and qr// provide different services to the programmer: #/o says 'Take this pattern and create a compiled regex that will not +change #for the life of the program' #qr// says 'Take this pattern and return a special object that I can a +ssign #to a variable, interpolate into another pattern, pass to a subroutine +, #etc, etc, and as a side-effect creates a compiled form that I can use + in #pattern matches directly.'

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: Precompiling qr/.../o question
by locked_user sundialsvc4 (Abbot) on Apr 03, 2008 at 13:50 UTC

    I haven't looked at the source-code myself, but I would expect for regular-expressions to be bound to a certain scope and for them to be cached ... say, by the expanded regular-expression string. Given a particular pattern to evaluate, you would first peek to see if it's in the cache and if so re-use it. It is my understanding that this is precisely what recent Perl implementations do.

      It is my understanding that this is precisely what recent Perl implementations do.

      Then your understanding is flawed. There's a cache, but it only holds one value: the last regexp compiled for that operator instance.

      >perl -Mre=debug -e"qr/$_/ for qw( foo bar bar foo )" 2>&1 | find "Com +piling" Compiling REx `foo' Compiling REx `bar' Compiling REx `foo'