Python 正则表达式中的无限循环以匹配 url

Python infinite loop in regex to match url

我正在尝试从文本文件中提取 URL 并陷入无限循环

import re

URL_PATTERN = re.compile(ur'''(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))''')

with open("some_text_file") as RAW:
    for line in RAW:
        RESULT = URL_PATTERN.findall(line)
        links = []
        for HTTP_TUPLES in RESULT:
            links.append(HTTP_TUPLES[0])

我怎样才能避免这种情况?

PS: 是的,我知道 urllib 和其他模块

尝试:

import re

URL_PATTERN = re.compile(ur'''(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))''')

RESULT = []
with open("some_text_file") as RAW:
  map(lambda x:RESULT.extend(URL_PATTERN.findall(x)), RAW.xreadlines())

在Python3中,删除xreadlines(),因为文件对象本身就是一个迭代器。

(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>'",]+|\(([^\s()<>'",]+|(\([^\s()<>'",]+\)))*\))+(?:\(([^\s()<>'",]+|(\([^\s()<>'",]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))

尝试 this.This 将完成 you.See 演示。

https://www.regex101.com/r/bC8aZ4/20

我没有在这个答案中解决正则表达式的正确性。您可能想查看 this article on URL 验证并为您的匹配任务自定义它。

问题

您的正则表达式包含 (A*)*.

形式的灾难性回溯的经典示例

例如,在这部分:

(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+

如果你扔掉第二个分支,你会立即看到问题:

(?:[^\s()<>]+)+

第二个分支也包含有问题模式的实例:

([^\s()<>]+|(\([^\s()<>]+\)))*

退化为:

([^\s()<>]+)*

为了演示这个问题,您可以在这个不匹配的字符串上测试您的正则表达式:

sdfsdf http://www/sdfsdfsdf(sdsdfsdfsdfsdfsdfsdf sfsdf(Sdfsdf)(sdfsdF)(sdfdsF)(<))sdsdfsf

Demo on regex101

解决方案

使用正则表达式中的上述代码段进行演示:

(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+
            ^             ^

在支持所有格量词的语言中,由于正则表达式的两个分支是互斥的,因此可以选择使这些量词具有所有格。

但是,由于Python不支持所有格量​​词,您可以在不影响结果的情况下删除标记位置的量词,因为它已经被最外层的量词处理了。

最终结果(处理了最后一组中的相同问题):

(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]|\(([^\s()<>]|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))

Demo on regex101