最近阅读了些别的部门的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 毫秒
最后
今天貌似又研究一把“茴香豆”的“茴香”的几种写法。
不过也没事,我明天可以拿着结论去找兄弟部门的开发抬杠了。
来源:麦叔编程