为什么使用用qr预编译的正则表达式比使用常量正则表达式慢?

caj*_*ine 4 perl

我刚才看到这个问题,大约在Perl优化特定的正则表达式。我想知道我的机器可以进行多少次匹配,因此我尝试了以下简单基准测试:

  • 情况1-使用预先编译的正则表达式 qr
  • 案例2-完全/regex/匹配
use 5.014;
use warnings;

use Benchmark qw(:all);

my $str = "SDZ";
my $qr = qr/S?T?K?P?W?H?R?A?O?\*?E?U?F?R?P?B?L?G?T?S?D?Z?/;

say "match [$&]" if( $str =~ $qr );

my $res = timethese(-10, {
    stdrx => sub { $str =~ /S?T?K?P?W?H?R?A?O?\*?E?U?F?R?P?B?L?G?T?S?D?Z?/ },
    qr_rx => sub { $str =~ $qr },
});

cmpthese $res;
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,结果如下:

use 5.014;
use warnings;

use Benchmark qw(:all);

my $str = "SDZ";
my $qr = qr/S?T?K?P?W?H?R?A?O?\*?E?U?F?R?P?B?L?G?T?S?D?Z?/;

say "match [$&]" if( $str =~ $qr );

my $res = timethese(-10, {
    stdrx => sub { $str =~ /S?T?K?P?W?H?R?A?O?\*?E?U?F?R?P?B?L?G?T?S?D?Z?/ },
    qr_rx => sub { $str =~ $qr },
});

cmpthese $res;
Run Code Online (Sandbox Code Playgroud)

即平原$str =~ /regex/比使用快50%$str =~ qr。我期望相反的结果。

难道我做错了什么?为什么我得到这个结果?

编辑:

刚刚下载了引用的书,我有很多东西要学习:)。但是,引用的书还说:

如果正则表达式文字没有变量插值,则Perl知道该正则表达式不能随使用而改变,因此,在正则表达式编译一次之后,该编译形式将被保存(“缓存”),以供再次执行相同代码时使用。不论程序执行过程中使用它的频率如何,都只检查和编译一次正则表达式。

因此,在这两个正则表达式以上是字面不变量代换。因此,“预编译”正则表达式应该与普通正则表达式一样快。在示例中,它慢了50%。

池上解释了为什么$str =~ $qr速度较慢。(老实说,“慢”是不正确的术语,因为我们谈论的是几微秒... :))

但是perl文档说:

在qr()时刻将模式预编译为内部表示,避免了每次尝试匹配/ $ pat /时都需要重新编译模式。

从普通perl用户(“不是高级Perl僧侣”)的角度来看,这意味着:预编译您的模式-这样会更快,但是事实是-仅当regex包含一些“非静态”时,它才有用“ 部分...

老实说,我仍然没有完全理解这一点-但有一本书要学习。:)也许文档中还多了一句话-可以帮助初学者不要误解qr他们何时开始学习。

谢谢你们!

ike*_*ami 5

如果不对正则表达式模式进行插补,则会在编译时对其进行编译。qr//运算符中的正则表达式和stdrx插值中的匹配运算符都不是正则表达式,因此两者都在编译时进行编译。

qr_rx测试中花费的额外30秒用于“编译”第三个正则表达式:中的match运算符中的一个qr_rx。别忘了这$_ =~ $re是短命$_ =~ m/$re/。现在,当整个模式都由一个插值的预编译正则表达式组成时,实际上没有编译发生,因为这种情况是经过特殊处理的,但是显然仍然需要一些时间来哄骗匹配操作使用预编译的正则表达式。(也许需要克隆它?)

  • 感谢您的见解。但是这不是很奇怪吗?由此看来,在匹配操作中使用预编译的正则表达式(在运行时)而不重新编译正则表达式是不可能的。这意味着使用已编译的正则表达式再快不过了吗? (3认同)