四时宝库

程序员的知识宝库

震惊!正则这样用,性能会提升?(正则啥意思)


最近阅读了些别的部门的Python开发写的代码,发现他们部门的开发特爱用RE模块去处理字符串的逻辑。

而我是更喜欢用字符串自带的方法去处理。

我也向他们问了原因,为啥不用字符串的内置方法,而要使用正则?

他们说,第一他们习惯了这种写法,第二...在某些场景下使用正则,代码执行效率相对比使用字符串内置函数会高一点。

今天我给大家聊聊我从他们那取到的正则“三部真经”

re.finditer 代替 re.findall

在我初学Python正则的时候,我就发现re.findall特别好用而简便。

不用使用group方法提取数据,而且能做到“全匹配”。

import re

text = "Hello, my phone numbers are 123-456-7890 and 987-654-3210."

phone_numbers_findall = re.findall(r'\d{3}-\d{3}-\d{4}', text)
print("findall:", phone_numbers_findall)

# 输出结果:findall: ['123-456-7890', '987-654-3210']

但是在匹配数据非常大的时候,re.findall返回的列表会特别占内存空间。

所以当已知匹配的数据非常大的情况下,优先考虑使用re.finditer才是正解,因为它执行后返回的是一个迭代器对象

import re

text = "Hello, my phone numbers are 123-456-7890 and 987-654-3210."

phone_numbers_finditer = re.finditer(r'\d{3}-\d{3}-\d{4}', text)

print(type(phone_numbers_finditer)) # <class 'callable_iterator'>
print("finditer:")
for match in phone_numbers_finditer:
    print(match.group())

# 输出结果:
# finditer:
# 123-456-7890
# 987-654-3210

使用迭代器的好处,文本就不再赘述啦。

str.split 性能比 re.split 更优

我感觉这俩除了写法不同之外没什么区别。相比之下re.split的写法稍微会复杂点(因为要写pattern)。

import re

# 使用 re.split
text = "123-456-7890, 987-654-3210"
pattern = r'[-]'
result_re = re.split(pattern, text)
print("re.split:", result_re)
# re.split: ['123', '456', '7890, 987', '654', '3210']

# 使用 str.split
result_str = text.split('-')
print("str.split:", result_str)
# str.split: ['123', '456', '7890, 987', '654', '3210']

两者返回值也都是列表。

但...性能如何,我们需要测下。

import re
import time

times = 100000
text = "123-456-7890, 987-654-3210"

start_time = time.time()
for _ in range(times):  
    result_re = re.split(r'[-]', text, maxsplit=1, flags=re.IGNORECASE)

end_time = time.time()
execution_time = (end_time - start_time)* 100
print("re.split execution time:", execution_time, "milliseconds")

start_time = time.time()
for _ in range(times):  
    result_str = text.split('-')

end_time = time.time()
execution_time = (end_time - start_time)* 100
print("str.split execution time:", execution_time, "milliseconds")

分别执行了split100000次,得到结果:

re.split execution time: 5.420470237731934 milliseconds
str.split execution time: 1.855015754699707 milliseconds

分别执行了split10000000次,得到结果:

re.split execution time: 718.4126615524292 milliseconds
str.split execution time: 231.18553161621094 milliseconds

结论:使用str.split性能更优。(打脸)

复用的pattern,一定要预编译

这结论不是我随口说说的,官方文档明确记载:

验证下结论是否是正确的:

# 使用编译后的正则表达式
pattern_compiled = re.compile(r'\d{3}-\d{3}-\d{4}')

# 不使用编译的正则表达式
pattern_not_compiled = r'\d{3}-\d{3}-\d{4}'

完整测试代码:

import re
import time

times = 100000
# 使用编译后的正则表达式
pattern_compiled = re.compile(r'\d{3}-\d{3}-\d{4}')

# 不使用编译的正则表达式
pattern_not_compiled = r'\d{3}-\d{3}-\d{4}'

# 测试字符串
text = "123-456-7890, 987-654-3210, 555-123-4567"

# 使用编译后的正则表达式
start_time_compiled = time.time()
for _ in range(times):
    result_compiled = pattern_compiled.findall(text)
end_time_compiled = time.time()
execution_time_compiled = (end_time_compiled - start_time_compiled) * 1000

# 不使用编译的正则表达式
start_time_not_compiled = time.time()
for _ in range(times):
    result_not_compiled = re.findall(pattern_not_compiled, text)
end_time_not_compiled = time.time()
execution_time_not_compiled = (end_time_not_compiled - start_time_not_compiled) * 1000

# 打印执行时间
print("使用预编译的执行时间:", execution_time_compiled, "毫秒")
print("不使用预编译的执行时间:", execution_time_not_compiled, "毫秒")

循环100000次代码执行时间:

使用预编译的执行时间: 55.454254150390625 毫秒
不使用预编译的执行时间: 81.07376098632812 毫秒

循环10000000次代码执行时间:

使用预编译的执行时间: 6629.4105052948 毫秒
不使用预编译的执行时间: 9879.02545928955 毫秒

最后

今天貌似又研究一把“茴香豆”的“茴香”的几种写法。

不过也没事,我明天可以拿着结论去找兄弟部门的开发抬杠了。


来源:麦叔编程

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接