Regex 如何强制Perl重新编译一个使用“quot/o";随需应变?

Regex 如何强制Perl重新编译一个使用“quot/o";随需应变?,regex,perl,compilation,modifier,Regex,Perl,Compilation,Modifier,技术问题: $ 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++) {

技术问题:

$ 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
给定正则表达式:

my $regEx = qr{whatever$myVar}oxi; # Notice /o for "compile-once"
强制它按需重新编译的最有效方法是什么?(例如,当我从程序逻辑中知道,
$myVar
值已更改)而不删除
/o
,并且依靠Perl的内部智能自动重新编译

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

$string2 =~ s/$regEx//;
上下文是:

$ 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
  • 我有一个正则表达式,它是通过从配置文件中拖入相当长(>1k长)的字符串来构建的

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

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

  • 在mod_Perl下运行的Perl模块中,regex经常重复使用

    • 这意味着(再加上长度>1-2k的字符串)我必须使用“
      /o
      ”修饰符
      在正则表达式上强制编译一次,以避免Perl重复检查变量值是否更改的性能影响(由于正则表达式是如上所示的
      s//
      的一部分,而不是单独作为匹配项使用,因此此启发式方法来自)

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

更新:下面是我为什么需要
/o
-没有它,正则表达式在每次循环迭代中都会重新编译(因此必须进行检查);没有它:

$ 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

$perl-e'{for(my$i=0;$i您基本上回答了自己的问题。使用
qr{…}
创建一个已编译的regexp对象,然后使用它:

my $re = qr{...};

...

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

...

if ($time_to_recompile) {
    $re = qr{...};
}
您甚至不需要“/o”修饰符。

当我从程序逻辑知道$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中重新编译的字符串值重新编译正则表达式。 或者只是

$myVar = ...;
...
s/$myVar/.../
据perlop说

“o”修饰符的效果不是 传播的,仅限于那些 模式显式地使用它

所以如果你写

my $str = 'x';
my $re  = qr/$str/o;
...
if (s/$re//) {
    ...
}
Perl在执行
s//
时仍会检查
$re
是否已更改。
/o
承诺编译
$re
时使用的
$str
值不会更改,因此,如果重新执行
qr/
,即使
$str
已更改,也会得到相同的结果ged。您可以在
使用“重新调试”时看到这一点:

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

我认为这不起作用。您代码中的第二个块经常执行,而且据我所知g它会尝试检测插值变量的值是否每次都改变。@Nemo-我现在知道问题出在哪里了。我忽略了提到我代码中的正则表达式不是以纯
$str=~$re
的方式使用的,而是以一种替代方式使用的:
$str=~s/$re/
。除非我不理解文档,否则这意味着正则表达式将被重新使用在没有
/o
的情况下编译每个替换,即使您给出的代码示例不会。我用示例用法更新了Q。我不这么认为。但是尝试一个实验很容易…设置
$re=qr{…}
其中,
..
取决于某个字符串
$s
,然后修改
$s
,然后执行
s/$re/
。如果它使用原始字符串,则最好将其编译。最坏的情况下,只需使用
/o
,如
我的$re=qr{…}/o
中所述。当您要重新编译时,只需分配
$re=qr{…}/o
@DVK:当然可以——每次循环都显式地重新编译正则表达式。