如何用Spacy Matcher结合正则跨token匹配externalize类动词后15字符内的名词
实现方案
核心调整思路如下:
- 用词根匹配锁定所有
externalize的变位形式,无需手动枚举各种时态变形 - 放宽动词和目标名词的中间匹配限制,允许最多3个中间token(对应15字符以内的间隔长度)
- 额外增加字符间隔校验逻辑,确保匹配结果严格符合间隔要求
- 直接返回原文本匹配片段,替换原有词根拼接逻辑,和预期输出格式对齐
完整可运行代码
import spacy from spacy.matcher import Matcher nlp = spacy.load("en_core_web_sm") matcher = Matcher(vocab = nlp.vocab) # 自定义匹配规则 pattern = [ {"LEMMA": "externalize", "POS": "VERB"}, # 匹配所有externalize的变位动词 {"OP": "{0,3}"}, # 允许动词和名词之间最多3个任意token {"POS": {"IN": ["NOUN", "PROPN"]}} # 匹配名词作为结束标记 ] matcher.add("externalize_noun", [pattern]) phrases = [ 'children externalize their emotions through outward behavior', 'children externalize hidden emotions.', 'children externalize internalized emotions.', 'a child might externalize a hidden emotion through misbehavior', 'a kid might externalize some emotions through behavior', 'traumatized children externalize their hidden trauma through bad behavior.', 'The kid is externalizing internal traumas', 'A child might externalize emotions though his outward behavior', 'The kid externalized a lot of his emotions through misbehavior.' ] list_result = [] for phrase in phrases: doc = nlp(phrase) matches = matcher(doc) for match_id, start, end in matches: span = doc[start:end] # 计算动词后的间隔字符数:整个匹配段长度减去动词本身长度 gap_length = len(span.text) - len(doc[start].text) if gap_length < 15: # 去掉末尾的标点,和预期结果格式对齐 matched_text = span.text.rstrip('.!?,') if matched_text not in list_result: list_result.append(matched_text) # 输出结果 for res in list_result: print(res)
关键改动说明
- 匹配规则优化:原来的规则只能匹配任意动词后紧跟的名词,调整后首先限定了动词词根必须是
externalize,同时允许中间最多存在3个任意token,覆盖了15字符以内的间隔场景 - 新增间隔校验:通过计算匹配段长度和动词本身长度的差值,严格过滤间隔超过15字符的匹配结果,避免规则放宽后匹配到不符合要求的内容
- 输出逻辑调整:直接取匹配片段的原文本,不再做词根转换,同时去掉末尾多余的标点,和预期输出格式完全一致
内容的提问来源于stack exchange,提问作者Akbar Hussein
相关产品推荐
相关产品推荐

