你如何迫使Perl重新编译一个用“/ o”编译的正则表达式?

时间:2011-06-01 18:39:53

标签: regex perl compilation modifier

技术问题:

鉴于正则表达式:

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

强制它重新编译按需的最有效方法是什么? (例如,当我从程序逻辑中知道$myVar值已更改)而不删除/o并依赖于Perl的内部智能来自动重新编译?

注意:正则表达式用于替换,这可能会影响重新编译规则sans / o:

$string2 =~ s/$regEx//;

上下文是:

  • 我有一个正则表达式,它是通过从配置文件中插入一个相当长(> 1k长)的字符串构建的。

    • 该文件每60分钟重新读取一次。

    • 如果从文件读取的字符串发生更改(通过更改文件时间戳,已定义),我想使用{{1}中重新标记的字符串值重新编译正则表达式}。

  • 在mod_perl下运行的Perl模块中重复使用正则表达式。

    • 这意味着(加上字符串长度> 1-2k)我必须使用“$myVar”修饰符强制在正则表达式上编译一次,避免Perl的性能损失反复检查变量值是否发生变化(此启发式算法来自perlop qr//,因为正则表达式用作/o的一部分,如上所示,而不是单独作为匹配)。

    • 这反过来意味着,当我知道变量在1小时内重新变换后变化时,我需要强制正则表达式重新编译,尽管s///修饰符。

更新:以下是我需要/o的原因的说明 - 没有它,每次循环迭代都会重新编译正则表达式(因此必须进行检查);它不是:

/o

3 个答案:

答案 0 :(得分:4)

当我从程序逻辑中知道$ myVar值改变
时 如果模式未更改,则

m//s///qr// 编译。要获得所请求的行为,您只需删除/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"

因此,

如果从文件读取的字符串发生更改(通过更改文件时间戳定义),我想使用$ myVar中的重新slurped字符串值重新编译正则表达式。
my $new_myVar = ...;
if ($myVar ne $new_myVar) {
   $re = qr/$new_myVar/;
   $myVar = $new_myVar;
}
...
s/$re/.../

或只是

$myVar = ...;
...
s/$myVar/.../

答案 1 :(得分:3)

你基本上回答了自己的问题。使用qr{...}创建一个已编译的regexp对象,然后使用它:

my $re = qr{...};

...

if ($str =~ $re) {
   # this used the statically compiled object
}

...

if ($time_to_recompile) {
    $re = qr{...};
}

您甚至不需要“/ o”修饰符。

答案 2 :(得分:2)

根据perlop

  

'o'修饰符的效果不是   传播,限于那些   明确使用它的模式。

所以,如果你写

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

在执行$re时,Perl仍会检查s///是否已更改。 /o充当承诺,$str编译中使用的$re的值不会改变,因此如果您重新执行qr//,您将获得相同的结果即使$str已更改。您可以通过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//; 
}

使用/o修饰符,您只能在第一次循环“设置$ re”后看到“编译REx ...”。没有它,你会在每次迭代中看到它。

外卖是,如果要在运行时更改模式,则不应使用/o。它不会影响s///,它会阻止您在需要时重新编译$re