如何优化 Python 正则表达式的性能?

pythonserver side programmingprogramming更新于 2024/2/12 5:17:00

简介

Python 中有一个专门用于正则表达式的内置库 re,你只需要导入它就可以使用它的功能(例如 search、match、findall 等),它们会返回一个 Match 对象,其中包含一些有用的技巧来修改结果。

根据维基百科,正则表达式(也称为 regexp)是指定搜索模式的字符集合,是一种可以过滤、提取或更改一系列字符的工具。人们还发现,使用"in"运算符时,正则表达式的运行速度更快。

正则表达式存在性能问题,通常很难调试和维护。要提高其性能,必须解决这些问题。

示例

import re my_string = 'I like tortilla.' # 'like (\w+)' is a regexp that matches 'like' followed by a space followed by # any number of word characters ('\w' means 'word character' and '+' means '1 or more'), # putting those word characters in a capture group (the parenthesis) regex_result = re.search(r'like (\w+)', my_string) print(regex_result.groups())

输出

('tortilla',)

Soundex 函数首先检查输入是否为非空字符串。最好的方法是什么?

如果您回答"正则表达式",请坐在角落里思考您的错误直觉。正则表达式很少是正确的答案;应尽可能避免使用它们。不仅出于性能原因,还因为它们难以调试和维护。此外,出于性能原因。

来自 soundex/stage1/soundex1a.py 的此代码片段检查函数参数源是否是一个完全由字母组成的单词,其中至少有一个字母(不是空字符串)−

为什么正则表达式效率很重要?

设计不良的正则表达式可能需要很长时间才能执行并严重减慢系统速度,即使精心设计的正则表达式可能非常有效。 BMC Discovery 经历了多次升级,使其比早期版本更能抵抗无效的正则表达式。

当应用于适度较大的字符串时,设计一个需要数小时、数天甚至整个宇宙才能完成的正则表达式是完全可以想象的。此外,它将执行 TPL 模式的工作量分散到多个处理器上,这样即使一个处理器忙于处理冗长的正则表达式匹配,其他处理器也可以继续工作。

低效正则表达式的剖析

那么,如何创建无效的常用短语?一个问题是正则表达式回溯太远;如果正则表达式有多个重复运算符,则可能会发生这种情况。+、* 或 n、m 是重复运算符的示例。如果正则表达式进行了部分匹配但后来失败,则必须循环返回并尝试任何其他潜在的部分匹配,以防其中任何一个成功。

以将字符串 abc abc abc 与正则表达式 a.*b.*cd 匹配为例。由于字符串不包含 d,因此匹配永远不会成功。但是,在放弃之前,正则表达式仍然必须穷尽字母组合 a、b 和 c 的所有可能性。

"*abc* abc abc",

"*ab*c ab*c* abc",
"*ab*c abc ab*c*",
"*a*bc a*bc* abc",
"*a*bc a*b*c ab*c*",
"*a*bc abc a*bc*",
"abc *abc* abc",
"abc *ab*c ab*c*",
"abc *a*bc a*bc*",
"abc abc *abc*"

粗略地讲,正则表达式需要执行的比较次数与字符串的长度乘以可能的中间匹配次数成正比。

在此示例中,使用非贪婪运算符(即 a.*?b.*?cd)不会对匹配次数产生影响,因为正则表达式引擎仍然需要尝试每种组合。>

编写高效正则表达式的指南

考虑潜在的失败情况

当正则表达式无法完全匹配但存在多个部分匹配时,就会出现问题,如前面的实例所示。在编写正则表达式时,重要的是要考虑正则表达式失败时的操作方式以及成功时会发生什么。

尝试快速失败

如果正则表达式达到无法匹配所需目标的程度,请尝试使整个正则表达式失败。

分析 - 尤其是失败情况

为了确保您的正则表达式符合您的预期,验证它至关重要。但是,评估正则表达式对仅部分匹配的长字符串(例如兆字节长的随机字母字符串)的效率也很重要。

除非必要,否则不要使用组

当您使用括号括住正则表达式的一部分时,正则表达式引擎必须更加努力地保留组匹配的文本,以防以后需要它。因此,匹配过程可能会变慢,有时会慢四倍或更多。

如果您需要使用括号但不需要使用组的内容,例如重复正则表达式的一部分时,则可以使用括号的非分组变体 (?:)。

结论

有些人会反驳说,Pandas 更适合这类操作。但是,我认为它不会像我们构建的纯 Python 版本那样快,因为将数据集加载到 DataFrame 中需要更长的时间。

其他选项,例如使用正则表达式库或将数据分成多个部分并并行计数,可以进一步加快速度(与大数据中高度相关的算法 map-reduce 相关的策略)。


相关文章