如何让正则验证文本列表时不受关键词顺序限制并优化性能?
高效验证文本是否包含所有关键词(精确匹配、顺序无关)
问题背景
给定如下DataFrame:
import pandas as pd df = pd.DataFrame({'description': ['ij edf m-nop ij abc', 'abc ij mnop yz', 'yz yz mnop aa abc', 'i j y y abc xxx mnop y z', 'yz mnop ij kl abc uvwxyz', 'aaabc ijij uuu yz mnop']})
需要判断每行文本是否精确匹配所有关键词(单词边界,忽略中间字符,顺序无关)。原方案通过生成关键词的全排列构建正则,在5万行数据上耗时5-15分钟,关键词数量到6个时会生成720种排列,效率极低。
为什么原方案低效
全排列的数量是n!(n为关键词数),正则引擎需要逐个匹配所有排列分支,随着关键词数量增加,复杂度呈阶乘级增长,完全没必要。
优化方案
以下两种方案都能将效率提升几个数量级,处理5万行数据仅需几秒:
方案1:逐关键词独立验证(直观高效)
直接对每行文本检查所有关键词是否都存在(用单词边界确保精确匹配):
import re import pandas as pd df = pd.DataFrame({'description': ['ij edf m-nop ij abc', 'abc ij mnop yz', 'yz yz mnop aa abc', 'i j y y abc xxx mnop y z', 'yz mnop ij kl abc uvwxyz', 'aaabc ijij uuu yz mnop']}) keywords = ['abc', 'ij', 'mnop', 'yz'] # 为每个关键词生成带单词边界的匹配模式,用re.escape避免特殊字符干扰 pattern_list = [fr'\b{re.escape(key)}\b' for key in keywords] # 对每行文本,检查所有关键词都匹配 df['valid'] = df['description'].apply(lambda x: all(re.search(pat, x) for pat in pattern_list))
- 时间复杂度:O(N*K),N为行数,K为关键词数,远低于阶乘级复杂度。
- 优势:代码直观,容易调试,关键词数量不多时性能最优。
方案2:正则正向预查(单正则匹配)
用正则的正向预查(零宽断言),无需排列组合即可实现顺序无关的全关键词匹配:
import re import pandas as pd df = pd.DataFrame({'description': ['ij edf m-nop ij abc', 'abc ij mnop yz', 'yz yz mnop aa abc', 'i j y y abc xxx mnop y z', 'yz mnop ij kl abc uvwxyz', 'aaabc ijij uuu yz mnop']}) keywords = ['abc', 'ij', 'mnop', 'yz'] # 构建正向预查正则:每个(?=.*\bkey\b)检查文本中存在对应关键词 regex_pattern = '^' + ''.join([f'(?=.*\\b{re.escape(key)}\\b)' for key in keywords]) + '.*$' # 编译正则并开启re.DOTALL,让.匹配换行符(处理含换行的长文本) compiled_re = re.compile(regex_pattern, re.DOTALL) df['valid'] = df['description'].apply(lambda x: bool(compiled_re.search(x)))
- 原理:每个正向预查
(?=.*\bkey\b)会独立检查文本中存在该关键词,所有预查通过则整体匹配成功,完全不限制关键词顺序。 - 优势:将匹配逻辑封装为单个正则,适合需要复用规则的场景,处理带换行的文本更方便。
最终输出
两种方案都能得到符合预期的结果:
description valid 0 ij edf m-nop ij abc False 1 abc ij mnop yz True 2 yz yz mnop aa abc False 3 i j y y abc xxx mnop y z False 4 yz mnop ij kl abc uvwxyz True 5 aaabc ijij uuu yz mnop False
内容的提问来源于stack exchange,提问作者VERBOSE
相关产品推荐
相关产品推荐

