Python 与regexp匹配的URL在某些字符串上非常慢
这里是我的regexp,用于在一些字符串中查找URL(我需要域的组,因为进一步的操作基于域),我注意到在这个示例中,对于一些字符串'fffffffff',速度非常慢,我明显缺少一些东西Python 与regexp匹配的URL在某些字符串上非常慢,python,regex,url,performance,Python,Regex,Url,Performance,这里是我的regexp,用于在一些字符串中查找URL(我需要域的组,因为进一步的操作基于域),我注意到在这个示例中,对于一些字符串'fffffffff',速度非常慢,我明显缺少一些东西 >>> URL_ALLOWED = r"[a-z0-9$-_.+!*'(),%]" >>> URL_RE = re.compile( ... r'(?:(?:https?|ftp):\/\/)?' # protocol ... r'(?:www.)?' # w
>>> URL_ALLOWED = r"[a-z0-9$-_.+!*'(),%]"
>>> URL_RE = re.compile(
... r'(?:(?:https?|ftp):\/\/)?' # protocol
... r'(?:www.)?' # www
... r'(' # host - start
... r'(?:'
... r'[a-z0-9]' # first character of domain('-' not allowed)
... r'(?:'
... r'[a-z0-0-]*' # characters in the middle of domain
... r'[a-z0-9]' # last character of domain('-' not allowed)
... r')*'
... r'\.' # dot before next part of domain name
... r')+'
... r'[a-z]{2,10}' # TLD
... r'|' # OR
... r'(?:[0-9]{1,3}\.){3}[0-9]{1,3}' # IP address
... r')' # host - end
... r'(?::[0-9]+)?' # port
... r'(?:\/%(allowed_chars)s+/?)*' # path
... r'(?:\?(?:%(allowed_chars)s+=%(allowed_chars)s+&)*' # GET params
... r'%(allowed_chars)s+=%(allowed_chars)s+)?' # last GET param
... r'(?:#[^\s]*)?' % { # anchor
... 'allowed_chars': URL_ALLOWED
... },
... re.IGNORECASE
... )
>>> from time import time
>>> strings = [
... 'foo bar baz',
... 'blah blah blah blah blah blah',
... 'f' * 10,
... 'f' * 20,
... 'f' * 30,
... 'f' * 40,
... ]
>>> def t():
... for string in strings:
... t1 = time()
... URL_RE.findall(string)
... print string, time() - t1
...
>>> t()
foo bar baz 3.91006469727e-05
blah blah blah blah blah blah 6.98566436768e-05
ffffffffff 0.000313997268677
ffffffffffffffffffff 0.183916091919
ffffffffffffffffffffffffffffff 178.445468903
是的,我知道还有另一种解决方案可以使用非常简单的regexp(例如,包含点的单词)并在以后使用urlparse来获取域,但当我们在URL中没有协议时,urlparse无法按预期工作:
>>> urlparse('example.com')
ParseResult(scheme='', netloc='', path='example.com', params='', query='', fragment='')
>>> urlparse('http://example.com')
ParseResult(scheme='http', netloc='example.com', path='', params='', query='', fragment='')
>>> urlparse('example.com/test/test')
ParseResult(scheme='', netloc='', path='example.com/test/test', params='', query='', fragment='')
>>> urlparse('http://example.com/test/test')
ParseResult(scheme='http', netloc='example.com', path='/test/test', params='', query='', fragment='')
>>> urlparse('example.com:1234/test/test')
ParseResult(scheme='example.com', netloc='', path='1234/test/test', params='', query='', fragment='')
>>> urlparse('http://example.com:1234/test/test')
ParseResult(scheme='http', netloc='example.com:1234', path='/test/test', params='', query='', fragment='')
是的,预先设置http://也是一种解决方案(我仍然不能100%确定是否存在其他urlparse问题),但我很好奇这个regexp到底出了什么问题
。。。r'(?:'
…r'[a-z0-9]'#域的第一个字符('-'不允许)
…r'(?:'
域中间的R′[AZ-0~-]**特征
…r'[a-z0-9]'#域的最后一个字符('-'不允许)
…r')*'
在域名的下一部分前面加上“\.”点
…r')+'
如果集合#符号1和集合#符号2具有相同的符号,则不应使用这样的构造([set#u of#symbols#1]*[set#u of#symbols#2])
请尝试使用以下代码:
。。。r'(?:'
…r'[a-z0-9]'#域的第一个字符('-'不允许)
域中间的R′[AZ-0~-]**特征
…r'(?仅供参考,您还可以使用re.VERBOSE标志使其更具可读性
URL_RE = re.compile(r"""
(?:(?:https?|ftp):\/\/)? # protocol
(?:www.)? # www
( # host - start
(?:
[a-z0-9] # first character of domain('-' not allowed)
(?:
[a-z0-0-]* # characters in the middle of domain
[a-z0-9] # last character of domain('-' not allowed)
)*
\. # dot before next part of domain name
)+
[a-z]{2,10} # TLD
| # OR
(?:[0-9]{1,3}\.){3}[0-9]{1,3} # IP address
) # host - end
(?::[0-9]+)? # port
(?:\/%(allowed_chars)s+/?)* # path
(?:\?(?:%(allowed_chars)s+=%(allowed_chars)s+&)* # GET params
%(allowed_chars)s+=%(allowed_chars)s+)? # last GET param
(?:#[^\s]*)?
""" % { # anchor
'allowed_chars': URL_ALLOWED
},
re.IGNORECASE|re.VERBOSE
)
正则表达式让我的大脑受伤我的直觉是任何带有大量h或f(或更长子字符串)的搜索目标与模式开头匹配的字符串会发出刺耳的声音。您是否考虑过尝试通过将WhiteSpace指定的delimted标记化来预处理字符串,然后对这些标记运行更简单的正则表达式?尝试一行操作并不总是最快的方法。urlparse按预期工作。只是您传递的不是URL。“example.com”不是URL,“myshellserver:22”也不是URL。你必须准备好接受这种方法有时会产生误报,如果是这样,也许简单的word-with-a-dot正则表达式就可以了。否则我同意iamcchuckb正则表达式不会让我头疼,但请使用python的r”“。”“
制定长正则表达式时使用多行字符串语法!所有这些引号都让我头疼。(顺便说一句,您的正则表达式需要一些修复…)请参阅我在URI正则表达式上的文章:我正在研究这个问题的答案……这篇文章中有太多的打字错误,所以我放弃了我的答案。但是对于初学者来说,你想修复你的URL,它有一个未替换的破折号,包括从'$'
到'
的范围。速度问题是由于卡斯特你的子域表达式中有一个类似反向跟踪的结构(即(a*)*
)。在www之后,你还得到了一个未替换的点。谢谢,当更改这一行并修复拼写错误时@ridgerunner发现它工作得非常快:)