7

技術的な質問:

与えられた正規表現:

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

オンデマンドで強制的に再コンパイルする最も効果的な方法は何ですか? $myVar(たとえば、値が変更されたことをプログラムロジックから知っている場合) ドロップせず/oに、Perl の内部スマートに依存して自動再コンパイルしますか?

注: 正規表現は置換で使用され、/o を使用しない再コンパイル ルールに影響を与える可能性があります。

$string2 =~ s/$regEx//;

コンテキストは次のとおりです。

  • 構成ファイルからかなり長い (> 1k の長さ) 文字列を丸呑みすることによって構築された正規表現があります。

    • そのファイルは 60 分ごとに 1 回再読み取りされます。

    • ファイルから読み取った文字列が変更された場合 (ファイルのタイムスタンプを変更することで定義$myVar) 、.

  • この正規表現は、mod_perl の下で実行される Perl モジュールで繰り返し頻繁に使用されます。

    • これは、(文字列の長さが >1-2k であることと相まって) " " 修飾子を使用/oして、変数値が変更されたかどうかを繰り返しチェックする Perl のパフォーマンス ヒットを回避するために、正規表現でコンパイル ワンスを強制する必要があることを意味します (このヒューリスティックはperlop qr//、正規表現は、s///上記のように の一部として使用され、それ自体では一致として使用されません)。

    • つまり、変数を 1 時間で再スラープした後に変数が変更されたことがわかっている場合は、/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
4

3 に答える 3

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 の再取得された文字列値を使用して正規表現を再コンパイルしたいと考えています。
my $new_myVar = ...;
if ($myVar ne $new_myVar) {
   $re = qr/$new_myVar/;
   $myVar = $new_myVar;
}
...
s/$re/.../

あるいは単に

$myVar = ...;
...
s/$myVar/.../
于 2011-06-01T20:30:03.273 に答える
3

あなたは基本的にあなた自身の質問に答えました。qr{...}コンパイル済み正規表現オブジェクトを作成し、それを使用するために使用します。

my $re = qr{...};

...

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

...

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

「/o」修飾子も必要ありません。

于 2011-06-01T18:42:57.607 に答える
2

パーロップによると

「o」修飾子の効果は伝播されず、明示的に使用するパターンに制限されます。

だからあなたが書くなら

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

Perl は$res///. は、 のコンパイルで使用される/oの値が変更されないという約束として機能するため、 を再実行すると、 が変更されても同じ結果が得られますこれを実際に見ることができます:$str$reqr//$struse 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と、最初のループで "Setting $re" の後に "Compiling REx..." のみが表示されます。それがなければ、反復ごとに表示されます。

要点は、実行時にパターンを変更したい場合は、 を使用すべきではないということ/oです。には影響せず、必要なときs///に再コンパイルできなくなります。$re

于 2011-06-01T20:56:28.267 に答える