Perl正则expression式的“o”修饰符是否仍然可以提供任何好处?

在Perl正则expression式的末尾包含'o'修饰符被认为是有益的。 目前的Perl文档甚至没有列出它,当然不在perlre的修饰符部分 。

它现在提供什么好处吗?

如果没有其他的话,这为了向后兼容的原因。


正如JA Faucett和brian d foy所指出的那样,如果你find正确的地方(其中一个不是perlre文档),那么“o”修饰符仍然是有logging的。 这是在perlop页面中提到的。 它也可以在perlreref页面find。

正如Alan M在接受的答案中指出的,更好的现代技术通常是使用qr //(引用正则expression式)运算符。

我相信它仍然支持,但它已经过时了。 如果你想只编译一次正则expression式,你最好使用正则expression式对象,如下所示:

 my $reg = qr/foo$bar/; 

$bar的插值是在variables被初始化的时候完成的,所以你将一直在使用封闭范围内的caching编译正则expression式。 但是有时你想要重新编译正则expression式,因为你希望它使用variables的新值。 这是Friedl在The Book中使用的例子:

 sub CheckLogfileForToday() { my $today = (qw<Sun Mon Tue Wed Thu Fri Sat>)[(localtime)[6]]; my $today_regex = qr/^$today:/i; # compiles once per function call while (<LOGFILE>) { if ($_ =~ $today_regex) { ... } } } 

在函数的范围内,$ today_regex的值保持不变。 但是下一次该函数被调用时,正则expression式将被重新编译为$today的新值。 如果他刚刚使用过

 if ($_ =~ m/^$today:/io) 

…正则expression式永远不会被更新。 所以,对于对象forms,您可以在不牺牲灵活性的情况下使用/ o的效率。

/o修饰符在perlop文档中,而不是perlre文档,因为它是一个引用类修饰符而不是正则expression式修饰符。 这对我来说一直都很奇怪,但事实就是如此。 自Perl 5.20以来,现在列在perlre中,只是注意到你可能不应该使用它。

在Perl 5.6之前,即使variables没有改变,Perl也会重新编译正则expression式。 你不需要这样做了。 尽pipe进一步修改了variables,你可以使用/o来编译一次正则expression式,但是正如其他答案所指出的那样, qr//是更好的select。

在Perl 5的20.0文档http://perldoc.perl.org/perlre.html中指出;

 Modifiers Other Modifiers … o - pretend to optimize your code, but actually introduce bugs 

这可能是一个幽默的说法,它应该进行某种优化,但实现被打破。

因此,select可能是最好的避免。

在正则expression式包含一个variables引用的情况下,这是一个优化。 它表明正则expression式即使在它内部有一个variables也不会改变。 这允许优化,否则将是不可能的。

以下是调用匹配的不同方式的时间。

 $ perl -v | grep version This is perl 5, version 20, subversion 1 (v5.20.1) built for x86_64-linux-gnu-thread-multi $ perl const-in-re-once.pl | sort 0.200 =~ CONST 0.200 =~ m/$VAR/o 0.204 =~ m/literal-wo-vars/ 0.252 =~ m,@{[ CONST ]},o 0.260 =~ $VAR 0.276 =~ m/$VAR/ 0.336 =~ m,@{[ CONST ]}, 

我的代码:

 #! /usr/bin/env perl use strict; use warnings; use Time::HiRes qw/ tv_interval clock_gettime gettimeofday /; use BSD::Resource qw/ getrusage RUSAGE_SELF /; use constant RE => qr{ https?:// (?:[^.]+-d-[^.]+\.)? (?:(?: (?:dev-)? nind[^.]* | mr02 )\.)? (?:(?:pda|m)\.)? (?:(?:news|haber)\.) (?:.+\.)? yandex\. .+ }x; use constant FINAL_RE => qr,^@{[ RE ]}(/|$),; my $RE = RE; use constant ITER_COUNT => 1e5; use constant URL => 'http://news.trofimenkov.nerpa.yandex.ru/yandsearch?cl4url=www.forbes.ru%2Fnews%2F276745-visa-otklyuchila-rossiiskie-banki-v-krymu&lr=213&lang=ru'; timeit( '=~ m/literal-wo-vars/', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m{ ^https?:// (?:[^.]+-d-[^.]+\.)? (?:(?: (?:dev-)? nind[^.]* | mr02 )\.)? (?:(?:pda|m)\.)? (?:(?:news|haber)\.) (?:.+\.)? yandex\. .+ (/|$) }x } } ); timeit( '=~ m/$VAR/', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^$RE(/|$), } } ); timeit( '=~ $VAR', ITER_COUNT, sub { my $r = qr,^$RE(/|$),o; for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ $r } } ); timeit( '=~ m/$VAR/o', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^$RE(/|$),o } } ); timeit( '=~ m,@{[ CONST ]},', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^@{[ RE ]}(/|$), } } ); timeit( '=~ m,@{[ CONST ]},o', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^@{[ RE ]}(/|$),o } } ); timeit( '=~ CONST', ITER_COUNT, sub { my $r = qr,^$RE(/|$),o; for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ FINAL_RE } } ); sub timeit { my ($name, $iters, $code) = @_; #my $t0 = [gettimeofday]; my $t0 = (getrusage RUSAGE_SELF)[0]; $code->(); #my $el = tv_interval($t0); my $el = (getrusage RUSAGE_SELF)[0] - $t0; printf "%.3f\t%-17s\t%.9f\n", $el, $name, $el / $iters } 

有一件事神秘莫测,就是允许一个ONCE块,至less在5.8.8。

perl -le 'for (1..3){ print; m/${\(print( "between 1 and 2 only"), 3)}/o and print "matched" }'