下面我有一个相当复杂的正则表达式,它似乎永远不会终止。这不仅仅是花费很长时间的问题-我已经等了几分钟才没有运气。

下面是一些重现该问题的代码:

import re
link = re.compile(u'(?i)((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?\xab\xbb\u201c\u201d\u2018\u2019]))', re.IGNORECASE)
text = "Check out this link http://ru.wikipedia.org/wiki/%D0%9B%D0%BE%D0%B2%D0%B5%D1%86_%D1%81%D0%BD%D0%BE%D0%B2_(%D0%B0%D0%BC%D1%83%D0%BB%D0%B5%D1%82"
matches = re.findall(link, text)


这是将re.DEBUG作为标志传递给模式的输出:

subpattern 1
  subpattern None
    branch
      literal 104
      literal 116
      literal 116
      literal 112
      max_repeat 0 1
        literal 115
      literal 58
      literal 47
      literal 47
    or
      literal 119
      literal 119
      literal 119
      max_repeat 0 3
        in
          category category_digit
      literal 46
    or
      max_repeat 1 4294967295
        in
          range (97, 122)
          range (48, 57)
          literal 46
          literal 45
      literal 46
      max_repeat 2 4
        in
          range (97, 122)
      literal 47
  max_repeat 1 4294967295
    subpattern None
      branch
        max_repeat 1 4294967295
          in
            negate None
            category category_space
            literal 40
            literal 41
            literal 60
            literal 62
      or
        literal 40
        max_repeat 0 4294967295
          subpattern None
            branch
              max_repeat 1 4294967295
                in
                  negate None
                  category category_space
                  literal 40
                  literal 41
                  literal 60
                  literal 62
            or
              subpattern None
                literal 40
                max_repeat 1 4294967295
                  in
                    negate None
                    category category_space
                    literal 40
                    literal 41
                    literal 60
                    literal 62
                literal 41
        literal 41
  subpattern None
    branch
      literal 40
      max_repeat 0 4294967295
        subpattern None
          branch
            max_repeat 1 4294967295
              in
                negate None
                category category_space
                literal 40
                literal 41
                literal 60
                literal 62
          or
            subpattern None
              literal 40
              max_repeat 1 4294967295
                in
                  negate None
                  category category_space
                  literal 40
                  literal 41
                  literal 60
                  literal 62
              literal 41
      literal 41
    or
      in
        negate None
        category category_space
        literal 96
        literal 33
        literal 40
        literal 41
        literal 91
        literal 93
        literal 123
        literal 125
        literal 59
        literal 58
        literal 39
        literal 34
        literal 46
        literal 44
        literal 60
        literal 62
        literal 63
        literal 171
        literal 187
        literal 8220
        literal 8221
        literal 8216
        literal 8217

最佳答案

如果将%D0%B5%D1%82去除字符串的末尾,它将起作用(尽管大约10s)。随着字符串和匹配项复杂度的增加,检查表达式条件所需的处理量呈指数增长,并且可能会将CPU的峰值消耗高达100%。

这称为catastrphic backtracking -在我看来,您遇到了99到100个问题;)



CPU被阻塞到无法继续处理表达式的地步。

解决方案:


简化您的表达方式(更可靠,更明智的选择),或者
在尝试验证样本之前先将其缩短/截断(这有点违反了使用表达式的目的)


老实说,我不知道这是否会帮您削减,但由于您有很多重叠的条件,因此看来可以减少它们。最好检查一堆样本以验证:

(?i)(?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)((?:\(?[^\s()<>]+\)?)*[^\s`!()\[\]{};:\'".,<>?\xab\xbb\u201c\u201d\u2018\u2019])


示例:http://regex101.com/r/lV0oL4

我相信您可以进一步简化它,但这只是一个快速的尝试。字符串的处理时间:少于100毫秒。

关于python - Python re.findall()不会终止,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21146406/

10-11 04:49