【问题标题】:Why does Perl backtracking match failure seem to take less time than match success?为什么 Perl 回溯匹配失败似乎比匹配成功花费的时间更少?
【发布时间】:2013-11-03 21:40:19
【问题描述】:

我有一个巨大的文件aab.txt,其内容是aaa...aab

让我大吃一惊

perl -ne '/a*bb/' < aab.txt

运行(匹配失败)比

perl -ne '/a*b/' < aab.txt

(匹配成功)。为什么????两者都应该首先吞噬所有的a,然后第二个立即成功,而第一个则必须一遍又一遍地回溯,以失败。

【问题讨论】:

  • 不需要&lt;。这就是-n 标志为您隐含的作用。
  • 谢谢回答者和评论者。我只能接受一个答案,但我应该两个都接受。

标签: regex perl


【解决方案1】:
/a*bb/

基本上是

/^(?s:.*?)a*bb/

注意两个*。除了优化之外,它是二次的。在最坏的情况下,(所有a的字符串),对于长度为N的字符串,它会检查当前字符是否为aN*(N-1)/2次。我们称之为 O(N2)。

值得在开始匹配之前扫描字符串 (O(N)) 以查看它是否可能匹配。匹配需要更长的时间,但匹配速度会更快。这就是 Perl 所做的。

当你运行以下命令时

perl -Mre=debug -e"'aaaaab' =~ /a*bb/"
  1. 你会得到关于模式编译的信息:

    Compiling REx "a*bb"
    synthetic stclass "ANYOF{i}[ab][{non-utf8-latin1-all}]".
    Final program:
       1: STAR (4)
       2:   EXACT <a> (0)
       4: EXACT <bb> (6)
       6: END (0)
    floating "bb" at 0..2147483647 (checking floating) stclass ANYOF{i}[ab][{non-utf8-latin1-all}] minlen 2
    

    最后一行表示它将在开始匹配之前在输入中搜索bb

  2. 您将获得有关模式评估的信息:

    Guessing start of match in sv for REx "a*bb" against "aaaaab"
    Did not find floating substr "bb"...
    Match rejected by optimizer
    

    您可以在此处看到该签入操作。

【讨论】:

    【解决方案2】:

    Perl 正则表达式被优化为尽可能早地失败,而不是尽可能快地成功。这在浏览大型日志文件时很有意义。

    有一个优化首先寻找字符串的常量部分,在这种情况下,“浮动”bbb。这可以相当有效地检查,而不必跟踪回溯状态。没有找到bb,匹配就在那里中止。

    b 并非如此。找到该浮动子字符串,并从那里构造匹配项。这是正则表达式匹配的调试输出(程序是"aaab" =~ /a*b/):

    Compiling REx "a*b"
    synthetic stclass "ANYOF_SYNTHETIC[ab][]".
    Final program:
       1: STAR (4)
       2:   EXACT <a> (0)
       4: EXACT <b> (6)
       6: END (0)
    floating "b" at 0..2147483647 (checking floating) stclass ANYOF_SYNTHETIC[ab][] minlen 1 
    Guessing start of match in sv for REx "a*b" against "aaab"
    Found floating substr "b" at offset 3...
    start_shift: 0 check_at: 3 s: 0 endpos: 4 checked_upto: 0
    Does not contradict STCLASS...
    Guessed: match at offset 0
    Matching REx "a*b" against "aaab"
    Matching stclass ANYOF_SYNTHETIC[ab][] against "aaab" (4 bytes)
       0 <> <aaab>               |  1:STAR(4)
                                      EXACT <a> can match 3 times out of 2147483647...
       3 <aaa> <b>               |  4:  EXACT <b>(6)
       4 <aaab> <>               |  6:  END(0)
    Match successful!
    Freeing REx: "a*b"
    

    您可以使用re pragma 的debug 选项获得此类输出。

    严格来说,查找bbb 是不必要的,但它可以让匹配更早地失败。

    【讨论】:

      猜你喜欢
      • 2019-12-07
      • 2011-08-31
      • 1970-01-01
      • 2021-01-06
      • 2019-01-27
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 2011-11-25
      相关资源
      最近更新 更多