为什么添加另外一个选项使我的正则表达式比600倍慢?

我在测试一个简单的Perl脚本时,注意到了 something weird,该脚本应该以某些前缀过滤掉文件名。

基本上,我正在构建一个这样的正则表达式:

my $regex = join "|",map quotemeta,@prefixes;
$regex = qr/^($regex)/;   # anchor the regex and precompile it

这里,在我最初测试的情况下,@prefixes由32个字符的十六进制字符串组成。我发现一切都运行良好,顺利达到6,552个前缀 – 但是一旦我尝试了6,553,the script的执行时间跳了25倍(从1.8秒到51秒)!

我玩弄了它,并构建了以下基准。我最初使用32字符的十六进制字符串,就像我原来的程序一样,但是发现如果我将字符串的长度减少到只有8个字符,阈值就会更高 – 到16,383,而减速因子显着更高:16,383个替代品的正则表达比只有16,382的速度慢几乎650倍!

#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(timethese cmpthese);

my $count = shift || 10;

our @items = map unpack("H8",pack "V",$_),0..99999;

our $nA = 16382; our $reA = join "|",@items[1 .. $nA];
our $nB = 16383; our $reB = join "|",@items[1 .. $nB];

$_ = qr/^($_)/ for $reA,$reB;  # anchor and compile regex

my $results = timethese( $count,{
    $nA => q{ our (@items,$nA,$reA); $nA == grep /$reA/,@items or die; },$nB => q{ our (@items,$nB,$reB); $nB == grep /$reB/,} );
cmpthese( $results );

以下是使用Perl(v5.18.2)在笔记本电脑上运行此基准测试的结果:

Benchmark: timing 10 iterations of 16382,16383...
     16382:  2 wallclock secs ( 1.79 usr +  0.00 sys =  1.79 CPU) @  5.59/s (n=10)
     16383: 1163 wallclock secs (1157.28 usr +  2.70 sys = 1159.98 CPU) @  0.01/s (n=10)
      s/iter  16383  16382
16383    116     --  -100%
16382  0.179 64703%     --

注意64,703%的速度差。

我的原始预感,基于6553和大约的数值巧合216/10,这可能在Perl正则表达式引擎中可能是一种任意限制,或者也许有一些10位结构的数组被限制为64 kB,或者​​是某种东西。但是,替代品的阈值数量取决于它们的长度这一事实使事情变得更加混乱。

(另一方面,它显然不仅仅是正则表达式的长度,原始的正则表达式具有6,553个32字节的替代方案是2 6,553×33 = 216,251字节长,而具有16,383个8字节的替代方案的正则表达式仅为2 16,383×9 = 147,450字节长)

什么是正则表达式匹配时间的这个奇怪的跳跃,为什么会发生在这个特定点?

长久以来,Perl的TRIE优化没有被应用到正则表达式的初始编译生成longjmp而不是jmp(我认为)指令(这取决于所涉及的字符串的交替数量和总长度,还有什么)更早?)在正则表达式中)。

看到区别:

perl -we'use re "debug"; qr/@{[join"|","a".."afhd"]}/'

perl -we'use re "debug"; qr/@{[join"|","a".."afhe"]}/'

您可以将您的交替分解成更小的块,并分别预编译它们。 (?? {$ RXA})|(?? {$ RXB})|(?? {$ RXC})。

相关文章

jquery.validate使用攻略(表单校验) 目录 jquery.validate...
/\s+/g和/\s/g的区别 正则表达式/\s+/g...
自整理几个jquery.Validate验证正则: 1. 只能输入数字和字母...
this.optional(element)的用法 this.optional(element)是jqu...
jQuery.validate 表单动态验证 实际上jQuery.validate提供了...
自定义验证之这能输入数字(包括小数 负数 ) <script ...