How do I get Perl to recompile a regular expression compiled with the "/ o" option on demand?

Technical question:

Given the regular expression:

my $regEx = qr{whatever$myVar}oxi; # Notice /o for "compile-once" 

What is the most efficient way to get it recompiled on demand ? (for example, when I know from the program logic that the value of $myVar changed), without discarding /o and depending on Perl’s internal skills for automatic recompilation?

NOTE. The regular expression is used in substitution, which can affect the sans / o recompilation rules:

 $string2 =~ s/$regEx//; 

Context:

  • I have a regular expression that is created by scrolling in a fairly long line β†’ 1k long from the configuration file.

    • This file is re-read every 60 minutes.

    • If the line read from the file changes (as defined by changing the timestamp of the file), I want to recompile the regular expression using the re-slurped string value in $myVar .

  • A regular expression is used repeatedly and often in a Perl module running under mod_perl.

    • This means that (in combination with a string length> 1-2k) I have to use the < /o modifier to force compilation in the regular expression to avoid performance improvements. Perl repeatedly checks to see if the variable value has changed (this heuristic from perlop qr// , since the regular expression is used as part of s/// , as shown above, and not by itself as a coincidence).

    • This, in turn, means that when I know that the variable has changed after re-applying it for 1 hour, I need to force re-compilation again, despite the /o modifier.

UPDATE. Here is an illustration of why I need /o - without it, the regular expression is recompiled (and therefore must be checked) for each iteration of the loop; with this NOT:

 $ perl -e '{for (my $i=0; $i<3; $i++) { my $re = qr{$i}oix; $s="123"; $s =~ s/$re//; print "i=$i; s=$s\n"; }}' i=0; s=123 i=1; s=123 i=2; s=123 $ perl -e '{ for (my $i=0; $i<3; $i++) { my $re = qr{$i}ix; $s="123"; $s =~ s/$re//; print "i=$i; s=$s\n"; }}' i=0; s=123 i=1; s=23 i=2; s=13 
+7
source share
3 answers
when I know from the program logic that the value of $ myVar has changed

m// , s/// and qr// only compile if the template does not change. All you have to do to get the requested behavior is to remove /o .

 $ perl -Mre=debug -e' qr/$_/ for qw( abc abc def def abc abc ); ' 2>&1 | grep Compiling Compiling REx "abc" Compiling REx "def" Compiling REx "abc" 

Thus,

If the line read from the file changes (as determined by changing the timestamp of the file), I want to recompile the regular expression using the re-slurped string value in $ myVar.
 my $new_myVar = ...; if ($myVar ne $new_myVar) { $re = qr/$new_myVar/; $myVar = $new_myVar; } ... s/$re/.../ 

or simply

 $myVar = ...; ... s/$myVar/.../ 
+4
source

You basically answered your question. Use qr{...} to create a compiled regular expression object, and then use it:

 my $re = qr{...}; ... if ($str =~ $re) { # this used the statically compiled object } ... if ($time_to_recompile) { $re = qr{...}; } 

You do not even need the modifier "/ o".

+3
source

According to perlop

The effect that the 'o' modifier has does not apply, limited to those templates that explicitly use it.

So if you write

 my $str = 'x'; my $re = qr/$str/o; ... if (s/$re//) { ... } 

Perl will still check if the value of $re has changed when s/// executed. /o acts as a promise that the value of $str used in compiling $re will not change, so if you qr// again, you will get the same result, even if $str has changed. This can be seen with use re 'debug' :

 use strict; use warnings; use re 'debug'; foreach my $i (0 .. 2) { my $s = '123'; print STDERR "Setting \$re\n"; my $re = qr/$i/o; print STDERR "Performing s///\n"; $s =~ s/$re//; } 

With the /o modifier, you will only see "Compiling REx ..." after "Installing $ re" for the first time through the loop. Without it, you will see every iteration.

The conclusion is that if you want to change the pattern at run time, you should not use /o . This will not affect s/// , and it will not allow you to recompile $re when you need to.

+2
source

All Articles