You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 12:27:03