如何使用spaCy对含TEI类XML标签的命名实体文本分词?
处理带TEI风格XML标签的spaCy分词问题
嘿,我懂你现在的困扰——直接把带<personName>这类标签的文本丢给spaCy,肯定会把标签拆成奇怪的零散token(比如<、personName、>),既打乱了正常分词逻辑,又浪费了原有的实体标注信息。下面给你一套实用的解决方案,一步步来搞定:
核心思路
先把XML标签和实际文本内容分离:提取出所有带标签的实体信息,生成纯文本让spaCy处理,之后再把原有的实体标注映射回spaCy的处理结果里。这样既保证分词、词性标注等操作正常,又能完整保留原有的实体标签信息。
完整代码示例
import spacy import re from spacy.tokens import Span # 加载spaCy英文模型(如果没装en_core_web_sm,先跑python -m spacy download en_core_web_sm) nlp = spacy.load('en_core_web_sm') # 你的带标签目标文本 txt = '<personName>Harry</personName> goes to <orgName>Hogwarts</orgName>. <personName>Sally</personName> lives in <locationName>London</locationName>.' # 1. 提取实体信息和纯文本内容 # 正则匹配<xxxName>内容</xxxName>格式,确保前后标签一致 tag_pattern = re.compile(r'<(\w+)Name>(.*?)</\1Name>') entities = [] # 存储(纯文本起始索引, 纯文本结束索引, 实体类型) pure_text = '' current_pos = 0 for match in tag_pattern.finditer(txt): # 把标签类型转成spaCy标准的大写格式(比如person→PERSON) ent_type = match.group(1).upper() # 获取标签包裹的实体内容 ent_text = match.group(2) # 把标签前的普通文本追加到纯文本中,再加上实体内容 pure_text += txt[current_pos:match.start()] + ent_text # 计算实体在纯文本中的起止位置 ent_start = len(pure_text) - len(ent_text) ent_end = len(pure_text) entities.append((ent_start, ent_end, ent_type)) # 更新当前处理位置到标签结束处 current_pos = match.end() # 追加文本最后一段无标签的内容 pure_text += txt[current_pos:] # 2. 用spaCy处理纯文本 doc = nlp(pure_text) # 3. 把原标签中的实体信息映射到spaCy的Doc对象中 # 保留spaCy自动识别的实体(不需要的话可以跳过这行) existing_ents = list(doc.ents) new_ents = [] for start, end, ent_type in entities: # 创建spaCy的Span对象,对应实体的位置和类型 span = Span(doc, start, end, label=ent_type) new_ents.append(span) # 合并并排序所有实体(按起始位置排序,避免重叠冲突) all_ents = sorted(existing_ents + new_ents, key=lambda x: x.start) doc.ents = all_ents # 测试输出:查看分词结果 print("分词结果:") for token in doc: print(f"{token.text:10} {token.pos_}") # 测试输出:查看实体信息 print("\n实体信息:") for ent in doc.ents: print(f"{ent.text:10} {ent.label_}")
代码说明
- 正则提取:用正则精准匹配格式统一的TEI实体标签,确保提取的实体内容和类型一一对应。
- 纯文本生成:剥离所有XML标签,让spaCy能基于纯自然语言完成正常的分词、词性标注等NLP操作。
- 实体映射:把原标签中的实体信息转换成spaCy标准的
Span对象,添加到doc.ents中,这样你既能利用spaCy的强大NLP功能,又能完整保留原有的实体标注。
如果你的文本存在嵌套标签,这个正则需要微调,但大部分TEI风格的实体标签都是非嵌套的,这个方案完全够用。
内容的提问来源于stack exchange,提问作者dimid
相关产品推荐
相关产品推荐

