MarkDown源中的正则表达式懒惰量词与否定类

时间:2010-11-11 19:11:29

标签: regex perl performance markdown

我正在查看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

2 个答案:

答案 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代码中看到。

而且,说实话,对于大多数用例来说,它并没有真正发挥那么大的作用。