Python正则如何实现含特殊字符化学实体的精确匹配多条件检索
我目前正在基于语料库使用化学命名实体构建机器学习训练数据集,涉及的化学场景均为真实业务场景而非虚构。现在需要构造符合以下规则的正则表达式:
- 以化学式字符串
2h-tetrazolium, 2,2'-(3,3'-dimethoxy[1,1'-biphenyl]-4,4'-diyl)bis[3-(4-nitrophenyl)-5-phenyl-,chloride (1:2)开头 - 后面接0到15个任意字符
- 后面接化学编码字符串
298-83-9 - 后面接0到15个任意字符
- 后面接1个非字母数字字符
- 后面接字符串
5 - 以非字母数字字符结尾
设置第5、7条非字母数字规则的原因是检索的文本内容冗长杂乱,需要避免5属于其他实体的情况,例如bluh bluh 298-83-9 bluh bluh 564或bluh bluh 298-83-9 bluh bluh 645这类场景。
我最初编写的正则表达式如下:
reg_exp = name_entity[0] + r".{0,15}\s*" + name_entity[1] + r".{0,15}\s*" + r"[^a-zA-Z\d]+" + name_entity[2] + r"[^a-zA-Z\d]+"
其中name_entity数组存储的是上述规则1、3、6对应的字符串。
但当前的问题是:规则1、3中的化学式和编码包含大量转义符、连字符等特殊字符,导致正则表达式无法正常匹配。我需要让正则将name_entity中的元素视为完全字面量短语,不解析其中的正则语法,使用的开发语言为Python。
附待匹配文本片段,其中加粗部分是预期匹配的内容:
"composition/information on ingredients substance / mixture : mixture substance name : nbt/bcip stock solution, mbf components chemical name cas-no. concentration (% w/w) methane, 1,1'-sulfinylbis- 67-68-5 >= 50 - < 70 2h-tetrazolium, 2,2'-(3,3'- dimethoxy[1,1'-biphenyl]-4,4'- diyl)bis[3-(4-nitrophenyl)-5-phenyl-, chloride (1:2) 298-83-9 >= 1 - < 5 actual concentration is withheld as a trade secret section 4. first aid measures general advice : do not leave the victim unattended. safety data sheet nbt/bcip stock solution version 3.0 revision date: 09-25-2019"
核心问题在于化学名称、CAS号中的[、]、(、)、-等字符均为正则语法中的特殊操作符,直接拼接会被正则引擎解析为规则而非普通字符串,使用Python内置的re.escape()函数即可自动对所有正则特殊字符做转义,将输入字符串识别为纯字面量。
修正后的完整代码如下:
import re # 按顺序存储:目标化学式、CAS号、目标数字"5" name_entity = [ "2h-tetrazolium, 2,2'-(3,3'-dimethoxy[1,1'-biphenyl]-4,4'-diyl)bis[3-(4-nitrophenyl)-5-phenyl-,chloride (1:2)", "298-83-9", "5" ] # 对每个实体字符串做转义处理,避免特殊字符被解析为正则语法 escaped_chem = re.escape(name_entity[0]) escaped_cas = re.escape(name_entity[1]) escaped_target_num = re.escape(name_entity[2]) # 适配示例文本中化学式的空格差异:将转义后的空格替换为匹配任意空白的规则,可匹配多个空格、换行等 escaped_chem = escaped_chem.replace(r"\ ", r"\s+") # 拼接最终正则,rf前缀同时支持变量插入和raw字符串规则 reg_exp = rf"{escaped_chem}.{{0,15}}{escaped_cas}.{{0,15}}[^a-zA-Z\d]{escaped_target_num}[^a-zA-Z\d]" # 测试匹配 test_text = """composition/information on ingredients substance / mixture : mixture substance name : nbt/bcip stock solution, mbf components chemical name cas-no. concentration (% w/w) methane, 1,1'-sulfinylbis- 67-68-5 >= 50 - < 70 2h-tetrazolium, 2,2'-(3,3'- dimethoxy[1,1'-biphenyl]-4,4'- diyl)bis[3-(4-nitrophenyl)-5-phenyl-, chloride (1:2) 298-83-9 >= 1 - < 5 actual concentration is withheld as a trade secret section 4. first aid measures general advice : do not leave the victim unattended. safety data sheet nbt/bcip stock solution version 3.0 revision date: 09-25-2019""" match_res = re.search(reg_exp, test_text) if match_res: print(f"匹配成功,匹配内容为:\n{match_res.group()}")
额外说明:
- 如果需要匹配的任意字符包含换行,可在匹配时添加
re.DOTALL参数:re.search(reg_exp, test_text, flags=re.DOTALL) - 正则中
[^a-zA-Z\d]严格匹配1个非字母数字字符,符合规则要求;如果允许连续多个非字母数字字符,可改为[^a-zA-Z\d]+ - 示例文本中的化学式和你给出的标准化学式存在空格差异,因此添加了
replace(r"\ ", r"\s+")的适配逻辑,如果你的待匹配文本中化学式格式完全统一,可以去掉这行。
内容的提问来源于stack exchange,提问作者Julia Penfield

