正则表达式未匹配全部结果:词典文本词性标识提取异常
嘿,我来帮你排查下问题——你的统计结果远低于实际次数,主要是两个核心问题:正则表达式的匹配范围太窄,加上代码逻辑只统计了每个定义里的最后一个匹配项!咱们一步步拆解修复:
1. 代码逻辑的致命问题:只取最后一个匹配项
先看你的这段代码:
temp_var = re.findall('\w+[.]+ ',split) if len(temp_var) >=1 : temp_var = temp_var.pop() # 这里只拿了最后一个匹配结果! typ_dict[temp_var] = typ_dict.get(temp_var,0) + 1
re.findall会返回当前定义里所有符合正则的匹配项,比如你给的Abnormal定义里有adj.、n.、adv.三个词性标识,但你用pop()只取了最后一个adv.,直接漏掉了前两个!这是统计次数严重偏低的最主要原因。
修复逻辑:遍历所有匹配结果
把代码改成遍历findall返回的每一个匹配项:
for row in cur: # 替换成你实际获取definition字段的方式,比如row[2]或者row['definition'] definition = row['definition'] # 先获取所有匹配的词性标识 matches = re.findall(r'\b([A-Za-z]+\.)\b', definition) # 逐个统计 for match in matches: # 可选:统一转小写,避免Adj.和adj.被分开统计 # match_norm = match.lower() # typ_dict[match_norm] = typ_dict.get(match_norm, 0) + 1 typ_dict[match] = typ_dict.get(match, 0) + 1 # 筛选高频结果 for key, count in typ_dict.items(): if count > 50: print(f"{key}: {count}")
2. 正则表达式的匹配缺陷
你的原正则\w+[.]+ 有几个限制:
- 强制要求后面跟空格:比如定义里的
n. (pl. -ies),n.后面是左括号不是空格,原正则完全匹配不到; \w+包含数字和下划线:可能会误匹配类似123.或者abc_.的非词性内容;[.]+匹配多个句号:虽然不影响,但词性标识一般都是单个句号,没必要匹配多个。
优化后的正则方案
推荐用这个正则来覆盖所有常见场景:
r'\b([A-Za-z]+\.)\b'
解释下各个部分:
\b:单词边界,确保我们匹配的是完整的词性标识(不会把abc.def.里的def.误当成词性);[A-Za-z]+:只匹配大小写字母,避免数字、下划线干扰;\.:精准匹配单个句号;- 末尾的
\b:允许词性标识后面跟空格、括号、逗号、分号、换行等任意非字母字符,覆盖所有定义里的常见格式。
如果想要更精准,可以用正向预查明确指定允许的后续字符:
r'([A-Za-z]+\.)(?=\s|\(|\)|,|;|\.|$)'
(?=\s|\(|\)|,|;|\.|$)表示匹配后面跟着空格、括号、逗号、分号、句号或者字符串结尾的情况,进一步减少误匹配。
验证示例
用你提供的测试文本:
Aback - adv. take aback surprise, disconcert. [old english: related to *a2]
Abm - abbr. Anti-ballistic missile
Abnormal - adj. Deviating from the norm; exceptional. abnormality n. (pl. -ies). Abnormally adv. [french: related to *anomalous]
修复后的代码会匹配到:adv.、abbr.、adj.、n.、adv.,总共5个匹配项,而原代码只会统计adv.、abbr.、adv.这3个,直接漏掉了adj.和n.——这就是你统计结果偏低的核心原因!
额外小建议
- 统一大小写:把匹配结果转成小写(
match.lower()),可以避免Adj.和adj.被当成两个不同的词性统计; - 后续手动核验:高频匹配结果里大概率都是真实的词性标识,少量非词性的缩写可以手动剔除,符合你的计划。
内容的提问来源于stack exchange,提问作者Ctrl

