gpt4 book ai didi

python - 2 个数量级的性能变化与看似很小的 python 正则表达式变化

转载 作者:太空宇宙 更新时间:2023-11-04 10:32:47 31 4
gpt4 key购买 nike

我有一个慢速的 python 正则表达式,如果我简单地删除正则表达式的最后一行,速度会提高两个数量级!这是我的重现示例:

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_REP2_RE 之间的唯一区别是附加的正则表达式。关于我做错了什么有什么想法吗?

最佳答案

是因为回溯;这是正则表达式效率低下的主要原因。

您删除的最后一行需要匹配至少 1 个数字或 M,后跟空格,以及沿途的许多可选内容。

倒数第二行:

((?P<gust_drct>\d+)\+?|(?P<gust_drct_miss>M))\s*\]?\s+

最初匹配最后一部分,即 60+ 和后面的空格,最后一行不留任何内容。因此,正则表达式无法匹配并一次回溯一个字符以尝试匹配最后一行。事实是,正则表达式会尝试匹配很多东西,并且对于正则表达式回溯的每个字符,都会有越来越多的匹配尝试。

在正则表达式匹配之前,它实际上已经拒绝了相当多的正则表达式前几行之前匹配的字符。


一个简单的例子是字符串 (10 a's):

aaaaaaaaaa

和正则表达式:

a+a+a+a+a+a+a+a+a+a+

正则表达式的第一部分 a+ 将匹配整个字符串(因为 + 是贪婪的),但是接下来,它需要匹配更多的 a 因为正则表达式的下一部分是 a+。然后引擎回溯一个字符,以便第一个 a+ 匹配 aaaaaaaaa(9 个 a),第二个匹配最后一个 a

接下来是第三个 a+ 并且由于没有更多的 a 可以匹配,正则表达式将回溯一个字符。由于第二个 a 无法回溯,它将是第一个 a+ 执行并匹配 aaaaaaaa(8 个 a),然后是第二个 a+ 将匹配最后一个 aa。现在没有更多的 a,所以第二个 a+ 将回溯以匹配倒数第二个 a,最后是第三个 a+ 可以匹配最后一个a

看看前 3 个 a+ 做了多少?现在想象一下,遍历每一个可能的匹配直到所有匹配?


通常,如果你根本不想回溯,你会使用原子组和所有格量词,但 python 不支持这些,至少 re 模块(regex 模块确实如此)。

您可能想要修改您的正则表达式并尝试查看它应该真正匹配什么,什么是真正可选的,尤其是您的捕获组中可能的空格。

关于python - 2 个数量级的性能变化与看似很小的 python 正则表达式变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25317391/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com