技术问题:
鉴于正则表达式:
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
答案 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
。