7

这个问题的灵感来自另一个问题。

比较:前者s/,(\d)/$1/使用s/,(?=\d)//捕获组仅替换数字而不替换逗号,后者使用前瞻来确定逗号是否被数字取代。如本答案所述,为什么后者有时更快?

4

2 回答 2

4

这两种方法做不同的事情并且有不同种类的间接费用。当您捕获时,perl 必须复制捕获的文本。无需消耗的前瞻匹配;它必须标记它开始的位置。您可以使用re 'debug'pragma 查看正在发生的事情:

use re 'debug';
my $capture = qr/,(\d)/;
编译 REx ",(\d)"
最终程序:
   1:精确(3)
   3:打开 1 (5)
   5:数字(6)
   6:关闭 1 (8)
   8:结束(0)
在 0 处锚定“,”(检查锚定) minlen 2
释放 REx: ",(\d)"
use re 'debug';
my $lookahead = qr/,(?=\d)/;
编译 REx ",(?=\d)"
最终程序:
   1:精确(3)
   3:IFMATCH[0] (8)
   5:数字(6)
   6:成功 (0)
   7:尾巴 (8)
   8:结束(0)
在 0 处锚定“,”(检查锚定) minlen 1
释放 REx: ",(?=\d)"

在大多数情况下,我希望前瞻比捕获更快,但正如其他线程正则表达式中所述,性能可能取决于数据。

于 2012-12-03T13:55:58.833 回答
-1

与往常一样,当您想知道两段代码中哪一段运行得更快时,您必须对其进行测试:

#!/usr/bin/perl

use 5.012;
use warnings;
use Benchmark qw<cmpthese>;

say "Extreme ,,,:";
my $Text = ',' x (my $LEN = 512);
cmpthese my $TIME = -10, my $CMP = {
    capture => \&capture,
    lookahead => \&lookahead,
};

say "\nExtreme ,0,0,0:";
$Text = ',0' x $LEN;
cmpthese $TIME, $CMP;

my $P = 0.01;
say "\nMixed (@{[$P * 100]}% zeros):";
my $zeros = $LEN * $P;
$Text = ',' x ($LEN - $zeros) . ',0' x $zeros;
cmpthese $TIME, $CMP;

sub capture {
    local $_ = $Text;
    s/,(\d)/$1/;
}

sub lookahead {
    local $_ = $Text;
    s/,(?=\d)//;
}

该基准测试了三种不同的情况:

  1. 仅有的 ','
  2. 只有',0'
  3. 1% ',0',其余 ','

在我的机器上和我的 perl 版本上,它会产生以下结果:

Extreme ,,,:
             Rate   capture lookahead
capture   23157/s        --       -1%
lookahead 23362/s        1%        --

Extreme ,0,0,0:
               Rate   capture lookahead
capture    419476/s        --      -65%
lookahead 1200465/s      186%        --

Mixed (1% zeros):
             Rate   capture lookahead
capture   22013/s        --       -4%
lookahead 22919/s        4%        --

这些结果证实了前瞻版本明显快于捕获的假设,除了几乎只有逗号的情况。正如 PSIAlt 在他的评论中已经解释的那样,这确实并不令人惊讶。

问候, 马蒂亚斯

于 2012-12-03T14:59:33.767 回答