我正在查看John Gruber在Perl中编写的MarkDown代码,并且有一个名为_Detab
的子代,它将制表符转换为空格,同时保留文本的缩进。有问题的代码行是Markdown.pl中的1314:
$text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge;
这不会导致不必要的回溯吗?以下模式不会更有效地执行吗?
/([^\t\n]*)\t/
或者我错过了什么?感谢。
顺便说一句,我只是否定\n
而不是\r
,因为所有换行符都预先标准化为\n
。
答案 0 :(得分:5)
不要猜测何时可以进行基准测试:
use Benchmark 'cmpthese';
my $source = "\t\thello\n\t\t\tworld\n" x 100;
my $g_tab_width = 8;
my ($textU, $textN);
cmpthese(-3, {
ungreedy => sub {
$textU = $source;
$textU =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge;
},
negated => sub {
$textN = $source;
$textN =~ s{([^\n\t]*)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge;
},
});
die "whoops" unless $textN eq $textU; # ensure they do the same thing
我发现非贪婪版本(显示在Markdown源代码中)比你建议的否定字符类快大约40%:
Rate negated ungreedy
negated 1204/s -- -30%
ungreedy 1718/s 43% --
我的猜测是匹配.
比否定字符类更有效,这可以弥补额外的回溯。需要更多的测试来证实这一点。
答案 1 :(得分:1)
你是对的。这会导致不必要的回溯。是的,你的模式会更有效率。
大多数人并不真正理解或思考正则表达式如何工作和/或只是按照他们的教学方式做事。我不知道此代码或作者的详细信息,但这是一个非常常见的正则表达式,您将在perl代码中看到。
而且,说实话,对于大多数用例来说,它并没有真正发挥那么大的作用。