Python中如何优化这个正则表达式?

下面这个正则:
re.findall(r’(?<!数量)\d+’,‘数量 123 单价 45 金额 5535’)
得到了结果:
[‘23’, ‘45’, ‘5535’]
我想以否定的模式来写,就是不想提取数量后面的数值,在结果的 list 里面数量那个 23 不应该出现的。
Python中如何优化这个正则表达式?

11 回复

自己研究写了一个出来。python 3
re.findall(r’[一-龥]+(?<!数量)(\d+)’,‘数量 123 单价 45 金额 5535’)
结果:
[‘45’, ‘5535’]


帖子标题没给出具体的正则表达式,所以没法直接优化。不过,哥们儿,正则表达式优化通常就那几招,我给你列个通用思路,你对着自己的表达式看看。

核心优化策略:

  1. 避免灾难性回溯:这是性能杀手。检查你的表达式里有没有 (.*)*(a+)+ 这种嵌套的量词(*, +, ?, {m,n})。有的话,尽量用更精确的匹配(比如 [^"]* 代替 .*?)或者用原子分组 (?>...) 来防止回溯。
  2. 使用非贪婪匹配要小心.*? 看起来省事,但引擎会尝试很多次“最短匹配”。如果上下文明确,用 [^x]*(匹配直到字符x)这种否定字符集通常更快。
  3. 编译重用:如果你在一个循环或多次调用里用同一个模式,一定要用 re.compile() 预编译它。
  4. 具体化你的模式:越具体越好。用 \d 代替 [0-9](其实一样),用 [A-Za-z] 代替 .* 来匹配字母。
  5. 使用 re.VERBOSE:写复杂的表达式时,用它加注释和换行,虽然不影响性能,但能让你自己看懂,便于维护和优化。
  6. 考虑不用正则:如果匹配需求很简单(比如固定字符串、前缀、后缀),直接用 str.find(), str.startswith(), str.endswith(),它们快得多。
  7. re.search() 代替 re.match():如果你不是非得从字符串开头匹配,re.search() 更灵活。但注意,re.match() 只在开头匹配,有时更快。

举个简单例子: 假设你想匹配引号内的内容,原表达式可能是 "(.+?)"。优化的话,可以改成 "([^"]*)"。后者用否定字符集 [^"] 直接匹配到下一个引号,避免了非贪婪 ? 的反复尝试。

代码示例(编译和具体化):

import re

# 不好的做法:在循环里重复编译
for text in text_list:
    match = re.search(r'\d{4}-\d{2}-\d{2}', text)  # 每次循环都编译

# 好的做法:预编译
date_pattern = re.compile(r'\d{4}-\d{2}-\d{2}')
for text in text_list:
    match = date_pattern.search(text)  # 用编译好的对象

一句话建议: 具体化模式、避免回溯、预编译重用。

因为匹配了 “数量 1 ”
re.findall(r’(?<!数量)\s(\d+)’,‘数量 123 单价 45 金额 5535’)

嗯,非常感谢大大

数量和\d 中间加个空格试试

其实字符串之间没有空格,我那个还是能起作用

(?<!数量\d*)\d+

空格是 V2 后台加的么?
python 的 re.findall 总有难以预想的情况
正常理解,「(?<!数量)\d+」和「(?<!数量)(\d+)」是一样的,似乎 python 里面有优先级的区别

你这个报错。提示 look-behind requires fixed-width pattern

确实后台加的。。\d+没括号就会捕捉带文字数值,应该是匹配整个 pattern 作为分组,带了括号就会只取得数字匹配括号分组。

编译器的锅好像,不支持不定长度。(?<!数量[0-9]{0,100000})[0-9]+这样就可以了

回到顶部