这个问题的灵感来自另一个问题。
比较:前者s/,(\d)/$1/
使用s/,(?=\d)//
捕获组仅替换数字而不替换逗号,后者使用前瞻来确定逗号是否被数字取代。如本答案所述,为什么后者有时更快?
这两种方法做不同的事情并且有不同种类的间接费用。当您捕获时,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)"
在大多数情况下,我希望前瞻比捕获更快,但正如其他线程正则表达式中所述,性能可能取决于数据。
与往常一样,当您想知道两段代码中哪一段运行得更快时,您必须对其进行测试:
#!/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)//;
}
该基准测试了三种不同的情况:
在我的机器上和我的 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 在他的评论中已经解释的那样,这确实并不令人惊讶。
问候, 马蒂亚斯