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 演示。
我没有在这个答案中解决正则表达式的正确性。您可能想查看 this article on URL 验证并为您的匹配任务自定义它。
问题
您的正则表达式包含 (A*)*
.
形式的灾难性回溯的经典示例
例如,在这部分:
(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+
如果你扔掉第二个分支,你会立即看到问题:
(?:[^\s()<>]+)+
第二个分支也包含有问题模式的实例:
([^\s()<>]+|(\([^\s()<>]+\)))*
退化为:
([^\s()<>]+)*
为了演示这个问题,您可以在这个不匹配的字符串上测试您的正则表达式:
sdfsdf http://www/sdfsdfsdf(sdsdfsdfsdfsdfsdfsdf sfsdf(Sdfsdf)(sdfsdF)(sdfdsF)(<))sdsdfsf
解决方案
使用正则表达式中的上述代码段进行演示:
(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+
^ ^
在支持所有格量词的语言中,由于正则表达式的两个分支是互斥的,因此可以选择使这些量词具有所有格。
但是,由于Python不支持所有格量词,您可以在不影响结果的情况下删除标记位置的量词,因为它已经被最外层的量词处理了。
最终结果(处理了最后一组中的相同问题):
(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]|\(([^\s()<>]|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))
我正在尝试从文本文件中提取 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 演示。
我没有在这个答案中解决正则表达式的正确性。您可能想查看 this article on URL 验证并为您的匹配任务自定义它。
问题
您的正则表达式包含 (A*)*
.
例如,在这部分:
(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+
如果你扔掉第二个分支,你会立即看到问题:
(?:[^\s()<>]+)+
第二个分支也包含有问题模式的实例:
([^\s()<>]+|(\([^\s()<>]+\)))*
退化为:
([^\s()<>]+)*
为了演示这个问题,您可以在这个不匹配的字符串上测试您的正则表达式:
sdfsdf http://www/sdfsdfsdf(sdsdfsdfsdfsdfsdfsdf sfsdf(Sdfsdf)(sdfsdF)(sdfdsF)(<))sdsdfsf
解决方案
使用正则表达式中的上述代码段进行演示:
(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+
^ ^
在支持所有格量词的语言中,由于正则表达式的两个分支是互斥的,因此可以选择使这些量词具有所有格。
但是,由于Python不支持所有格量词,您可以在不影响结果的情况下删除标记位置的量词,因为它已经被最外层的量词处理了。
最终结果(处理了最后一组中的相同问题):
(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]|\(([^\s()<>]|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))