使用Pandas str.contains时字符集与Em破折号的正则异常问题
军衔正则筛选异常的原因与解决方案
问题背景
使用Pandas的str.contains结合正则筛选低阶军衔时,原正则r'e[ -–]*[123]'(意图匹配e3、e 3、e-2、e––1这类格式)出现误匹配:
- 错误匹配了
E-6/ Petty Officer 1st class(因字符串中包含1st的1) - 错误匹配了
eajucbniuawbnciu1(因末尾的1)
测试代码及输出如下:
data = { 'Rank': ['E-3', 'e2', 'E 1', 'E7', 'E-5 ','e-6 petty officer 1st class'], } import pandas as pd filter_lower_enlisted = r'e[ -–]*[123]' participants = pd.DataFrame(data) parts_enlisted_low = participants[participants['Rank'].str.contains(filter_lower_enlisted, case=False, na=False)].reset_index(drop=True) print(parts_enlisted_low['Rank'])
输出:
0 E-3 1 e2 2 E 1 3 e-6 petty officer 1st class Name: Rank, dtype: object
异常原因
正则字符集[ -–]的写法存在本质问题:
短破折号(-)被放在了空格(ASCII 32)和Em破折号(Unicode 8212)之间,此时正则引擎会将其解析为字符范围(从ASCII 32到Unicode 8212),而非单独的短破折号字符。
这个范围覆盖了几乎所有可打印字符(包括字母、数字、普通符号等),导致[ -–]*可以匹配任意数量的这类字符。只要字符串中存在不区分大小写的e,且后续任意位置出现1/2/3,就会被错误匹配。比如e-6 petty officer 1st class中的1st的1、eajucbniuawbnciu1末尾的1,都触发了匹配。
可行解决方案
1. 调整短破折号在字符集的位置
将短破折号放在字符集的开头或结尾,避免被解析为范围:
# 短破折号放在开头 filter_lower_enlisted = r'e[- –]*[123]' # 或放在结尾 filter_lower_enlisted = r'e[ –-]*[123]'
2. 转义短破折号
在短破折号前添加反斜杠,明确标记为普通字符:
filter_lower_enlisted = r'e[ \-–]*[123]'
3. 拆分正则表达式
用或逻辑分隔不同分隔符的匹配规则,彻底规避字符范围问题:
filter_lower_enlisted = r'e[ –]*[123]|e[- ]*[123]'
4. 增强匹配严谨性(可选)
如果需要严格匹配军衔格式(而非字符串任意位置的e+1/2/3),可以添加边界限制:
- 匹配单词边界:确保
e和数字是一个独立的军衔标识filter_lower_enlisted = r'\be[- –]*[123]\b' - 匹配行开头:如果军衔总是出现在字符串开头
filter_lower_enlisted = r'^e[- –]*[123]'
内容的提问来源于stack exchange,提问作者Noot
相关产品推荐
相关产品推荐

