如何优化Python正则表达式的性能?
阅读更多:Python 教程
介绍
Python中存在一个专门的正则表达式内置库,名为re。只需导入它即可使用其功能(例如搜索、匹配、查找所有等)。它们将返回一个Match对象,其中包含有用的技术,可以修改您的结果。
根据维基百科,正则表达式(也称为regexp)是指定搜索模式的字符集。它是一个工具,可以使您过滤、提取或更改一系列字符。也已经发现,当使用“in”运算符时,正则表达式的性能更快。
正则表达式存在性能问题,通常很难进行调试和维护。为了提高其性能,这些问题必须得到解决。
示例
import re
my_string = 'I like tortilla.'
# 'like (\w+)'是一个正则表达式,匹配'like'后跟随空格,后跟随任意数量的单词字符('\w'表示'单词字符','+'表示'1个或多个'),
# 将这些单词字符放在一个捕获组中(括号)
regex_result = re.search(r'like (\w+)', my_string)
print(regex_result.groups())
输出
('tortilla',)
Soundex函数首先检查输入是否为非空字母字符串。最好的方法是什么?
如果您回答“正则表达式”,请坐在角落里思考一下您的错误直觉。正则表达式很少是正确答案;它们应尽可能避免。不仅是因为性能原因,而且因为它们很难调试和维护。另外,还有性能问题。
此来自soundex/stage1/soundex1a.py的代码片段检查函数参数源是否为完全由字母组成的单词,至少一个字母(而不是空字符串)−
为什么正则表达式的效率很重要?
一个设计不良的正则表达式可能需要很长时间才能执行,并严重减慢系统的速度,即使良好设计的正则表达式可能非常有效。 BMC Discovery已经进行了多次升级,以使其比早期版本更能抵抗无效的正则表达式。
当应用于相当大的字符串时,很可能设计出一种正则表达式,其完成需要数小时、数天甚至整个宇宙的存在时间。此外,它在多个处理器之间分发执行TPL模式的努力,以便其他处理器即使其中一个被占用进行较长时间的正则表达式匹配时,仍然可以继续工作。
无效正则表达式的解剖
那么,如何创建一个普遍的无效短语?一个问题是当正则表达式回溯太远时;这可能会发生在正则表达式具有多个重复操作符。+、*或n、m是重复操作符的示例。如果它进行了部分匹配但后来失败,那么它必须回路返回并尝试任何其他可能的部分匹配。
例如,考虑使用正则表达式a.b.cd来匹配字符串abc abc abc。由于该字符串不包含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中需要更长的时间。
其他选项,如使用regex库或将数据分成多个部分并并行计数,可以进一步加快速度(这是与大数据中高度相关的映射-减少算法相关的策略)。