过去认为在Perl正则表达式的末尾包含'o'修饰符是有益的。当前Perl documentation似乎甚至没有列出它,当然不是modifiers section of perlre。
它现在提供任何好处吗?
仍然被接受,出于向后兼容的原因,如果没有其他原因。
如J A Faucett和brian d foy所述,如果您找到合适的地方(其中一个不是perlre
文档),仍会记录'o'修饰符。在perlop页面中提到了它。它也可以在perlreref页面中找到。
正如Alan M在接受的答案中所指出的,更好的现代技术通常是使用qr //(引用的正则表达式)运算符。
答案 0 :(得分:37)
我确信它仍然受到支持,但它已经过时了。如果你想只编译一次正则表达式,你最好使用正则表达式对象,如下所示:
my $reg = qr/foo$bar/;
$bar
的插值是在初始化变量时完成的,因此您将始终在封闭范围内使用缓存的,已编译的正则表达式。但有时你想要重新编译正则表达式,因为你希望它使用变量的新值。以下是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的值保持不变。但是下次调用该函数时,将使用新值$today
重新编译正则表达式。如果他刚刚使用
if ($_ =~ m/^$today:/io)
......正则表达式永远不会更新。因此,使用对象形式,您可以在不牺牲灵活性的情况下获得/ o的效率。
答案 1 :(得分:17)
/o
修饰符位于perlop文档中,而不是perlre文档中,因为它是类似引号的修饰符而不是正则表达式修饰符。这对我来说似乎总是很奇怪,但事实就是如此。从Perl 5.20开始,它现在列在perlre中只是为了注意你可能不应该使用它。
在Perl 5.6之前,即使变量没有改变,Perl也会重新编译正则表达式。你不需要那样做了。尽管对变量进行了进一步更改,您仍可以使用/o
编译正则表达式,但正如其他答案所指出的那样,qr//
对此更好。
答案 2 :(得分:6)
在Perl 5版本20.0文档中 http://perldoc.perl.org/perlre.html 它说明了
Modifiers
Other Modifiers
…
o - pretend to optimize your code, but actually introduce bugs
这可能是一种幽默的说法,它应该执行某种优化,但实施却被打破了。
因此,最好避免使用该选项。
答案 3 :(得分:4)
这是正则表达式包含变量引用的情况下的优化。它表明正则表达式即使在其中有变量也不会改变。这允许以其他方式无法实现的优化。
答案 4 :(得分:2)
以下是调用匹配方式的不同方法。
$ 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
}
答案 5 :(得分:0)
奇怪的是,不做的一件事是,允许一个ONCE块,至少是5.8.8。
perl -le 'for (1..3){
print;
m/${\(print( "between 1 and 2 only"), 3)}/o and print "matched"
}'
答案 6 :(得分:0)
是和否
我使用以下脚本进行了简单的比较:
perl -MBenchmark=cmpthese -E 'my @n = 1..10000; cmpthese(10000, {string => sub{"a1b" =~ /a\d+c/ for @n}, o_flag => sub{"a1b" =~ /a\d+c/o for @n}, qr => sub{my $qr = qr/a\d+c/; "a1b" =~ /$qr/ for @n } })'
结果如下:
Rate qr string o_flag
qr 760/s -- -72% -73%
string 2703/s 256% -- -5%
o_flag 2833/s 273% 5% --
所以,/o 标志显然比使用 qr 快。
但显然 /o 标志可能会导致错误: Perl regex /o optimization or bug?