Python使用lxml为XML多词命名实体插入标注标签问题求助
XML实体标注多词匹配优化方案
现有问题根因
- 原有实现通过
itertools.zip_longest绑定词表项和文本单词的匹配逻辑完全错误,无法适配多词实体的跨位置匹配需求 - 无匹配优先级控制,短实体优先匹配会拆分长实体
- 没有跳过已匹配的多词实体对应的文本段,导致内容重复输出
优化后代码
from lxml import etree import re import string stylesheet = etree.XML(""" <xsl:stylesheet version="1.0" xmlns:btest="uri:bolder" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="@*"> <xsl:copy /> </xsl:template> <xsl:template match="*"> <xsl:element name="{name(.)}"> <xsl:copy-of select="@*" /> <xsl:apply-templates select="text()" /> <xsl:apply-templates select="./*" /> </xsl:element> </xsl:template> <xsl:template match="text()"> <xsl:copy-of select="btest:bolder(.)/node()" /> </xsl:template> </xsl:stylesheet> """) glossary = ['Paris', 'Vincennes', 'France', 'Guy de Maupassant', 'Maurice Ravel'] # 按实体长度倒序排序,优先匹配长实体 sorted_glossary = sorted(glossary, key=lambda x: len(x), reverse=True) # 生成正则匹配规则,限制实体边界避免部分匹配 pattern = re.compile('|'.join([rf'(?<!\w){re.escape(entity)}(?!\w)' for entity in sorted_glossary])) def bolder(context, s): results = [] text = s[0] last_pos = 0 root = etree.Element('r') for match in pattern.finditer(text): start, end = match.span() # 添加匹配前的普通文本 if start > last_pos: if len(root) == 0 and root.text is None: root.text = text[last_pos:start] else: # 追加到最后一个节点的tail if len(root) > 0: last_node = root[-1] last_node.tail = (last_node.tail or '') + text[last_pos:start] else: root.text = (root.text or '') + text[last_pos:start] # 添加实体标签 entity_node = etree.SubElement(root, 'entity') entity_node.text = match.group() last_pos = end # 添加最后一段剩余文本 if last_pos < len(text): if len(root) > 0: last_node = root[-1] last_node.tail = (last_node.tail or '') + text[last_pos:] else: root.text = (root.text or '') + text[last_pos:] results.append(root) return results def test(): ns = etree.FunctionNamespace('uri:bolder') ns['bolder'] = bolder transform = etree.XSLT(stylesheet) input_xml = """<TEI><teiHeader></teiHeader><body><p>Paris est la capitale de France et Vincennes n'est pas loin.</p><p> Guy de Maupassant et Maurice Ravel inaugurent une nouvelle statue à Paris.</p></body></TEI>""" new = str(transform(etree.XML(input_xml))) print(new) if __name__ == "__main__": test()
运行输出
<?xml version="1.0"?> <TEI><teiHeader/><body><p><entity>Paris</entity> est la capitale de <entity>France</entity> et <entity>Vincennes</entity> n'est pas loin.</p><p> <entity>Guy de Maupassant</entity> et <entity>Maurice Ravel</entity> inaugurent une nouvelle statue à <entity>Paris</entity>.</p></body></TEI>
完全符合预期标注要求,无重复、漏标问题。
内容的提问来源于stack exchange,提问作者Lter
相关产品推荐
相关产品推荐

