我有一个很慢的python正则表达式,如果我只删除regex的最后一行,速度会提高两个数量级!下面是我的复制示例:
import re
import timeit
mystr = "14923KMLI MLI2010010206581258 0.109 b M M M 0 09 60+ "
basere = r"""
(?P<wban>[0-9]{5})
(?P<faaid>[0-9A-Z]{4})\s
(?P<id3>[0-9A-Z]{3})
(?P<tstamp>[0-9]{16})\s+
\[?\s*((?P<vis1_coef>\-?\d+\.\d*)|(?P<vis1_coef_miss>M))\s*\]?\s*
\[?(?P<vis1_nd>[0-9A-Za-z\?\$/ ])\]?\s+
((?P<vis2_coef>\d+\.\d*)|(?P<vis2_coef_miss>[M ]))\s+(?P<vis2_nd>[A-Za-z\?\$ ])\s+
...............\s+
\[?\s*((?P<drct>\d+)|(?P<drct_miss>M))\s+
((?P<sknt>\d+)|(?P<sknt_miss>M))\s+
((?P<gust_drct>\d+)\+?|(?P<gust_drct_miss>M))\s*\]?\s+
"""
additional = r"""
\[?((?P<gust_sknt>\d+)R?L?F*\d*\+?|(?P<gust_sknt_miss>M))\s*\]?\s+
"""
P1_RE = re.compile(basere + additional, re.VERBOSE)
P2_RE = re.compile(basere, re.VERBOSE)
for myre in ["P1_RE", "P2_RE"]:
statement = "%s.match('%s')" % (myre, mystr)
res = timeit.timeit(statement, "from __main__ import %s" % (myre,),
number=1000)
print('%s took %.9f per iteration' % (myre, res / 1000.))
# result on my laptop, python 2.6 and 3.3 tested
# P1_RE took 0.001489143 per iteration
# P2_RE took 0.000019991 per iteration
因此P1_RE
和{
这是因为回溯;这是正则表达式效率低下的一个突出原因。在
删除的最后一行要求至少匹配1个数字或
M
,后面跟着空格,以及许多很多可选的东西。在倒数第二行:
最初匹配最后一部分,即
60+
和后面的空格,最后一行不留任何内容。因此,正则表达式无法匹配,并一次回溯一个字符以尝试匹配最后一行。问题是,正则表达式将尝试匹配很多内容,对于正则表达式回溯的每个字符,都有越来越多的尝试匹配。在在正则表达式匹配之前,它实际上已经拒绝了很多之前正则表达式行匹配过的字符。在
一个简单的例子是字符串(10个A):
^{pr2}$以及正则表达式:
regex的第一部分},因为regex的下一部分是
a+
将匹配整个字符串(因为+
是贪婪的),但是接下来,它需要匹配更多的{a+
。然后引擎回溯一个字符,使第一个a+
匹配aaaaaaaaa
(9a),第二个匹配最后一个a
。在下一个是第三个}将匹配最后一个{}。现在没有了
a+
,由于没有更多的a
匹配,regex将回溯一个字符。由于第二个a
无法回溯,因此第一个a+
与aaaaaaaa
(8a)匹配,第二个{a
,所以第二个a+
将回溯以匹配倒数第二个a
,最后,第三个a+
可以匹配最后一个a
。在看看前3
a+
做了多少?现在想象一下,通过每一个可能的匹配,直到所有匹配?在通常,如果您根本不想回溯,您可以使用原子组和所有格量词,但python不支持这些,至少,} 模块支持)。在
re
模块不支持这些功能(^{您可能需要修改regex并尝试查看它应该真正匹配什么,什么是真正可选的,尤其是捕获组中可能的空格。在
相关问题 更多 >
编程相关推荐