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

Python提取最长完整人名:现有代码错误排查与修正

问题:提取新闻人物实体时仅保留完整人名

我用Python解析新闻文章,提取其中的人物姓名集合。目前通过Stanford Stanza NLP库将所有分类为PER(人物)的命名实体添加到集合中,代码如下:

maxnames = set()  # 初始化存储PER实体的空集合
for entity in doc.entities:
    if entity.type == "PER":
         if entity.text not in maxnames:
             maxnames.add(entity.text)

实际运行后得到的集合示例:

{'von der Leyen', 'Meloni', 'Lars Danielsson', 'Filippo Mannino', 'Danielsson', 'Giorgia Meloni', 'Ursula von der Leyen', 'Matteo Piantedosi', 'Lamberto Giannini'}

我希望仅保留最完整的人名,处理后的集合应为:

{'Lars Danielsson', 'Filippo Mannino', 'Giorgia Meloni', 'Ursula von der Leyen', 'Matteo Piantedosi', 'Lamberto Giannini'}

原因:

  • 'von der Leyen' 应被 'Ursula von der Leyen' 替代
  • 'Meloni' 应被 'Giorgia Meloni' 替代,以此类推,只保留包含简称的完整人名。

我尝试编写了如下函数,但未能实现预期效果,恳请帮忙排查错误:

def longestname(reference: str, nameset: set[str]) -> set[str]:
    """
    返回集合中最长的人名
    """
    for name in nameset.copy():
        lenname = len(name)
        lenref = len(reference)
        if lenref < lenname:
            if reference in name:
                nameset.add(name)
            else:
                nameset.remove(name)
    nameset.add(reference)
    return nameset


nameset = set()
nameset = longestname("von der Leyen", nameset)
nameset = longestname("Meloni", nameset)
nameset = longestname("Lars Danielsson", nameset)
nameset = longestname("Lars", nameset)
nameset = longestname("Giorgia Meloni", nameset)
nameset = longestname("Ursula von der Leyen", nameset)
nameset = longestname("Giorgia", nameset)

print(nameset)
# 预期输出应为: 
# {'Lars Danielsson', 'Giorgia Meloni', 'Ursula von der Leyen'}

问题排查与修正

你的longestname函数存在几个关键逻辑漏洞:

  1. 判断逻辑不完整:只处理了新传入的短名字,没处理新传入长名字时需要移除对应短简称的情况。
  2. 冗余操作:nameset.add(name)完全多余,因为name本来就在集合里。
  3. 未覆盖反向包含场景:当新传入的长名字包含集合里的短名字时,没有移除那些短名字。

修正方案

方案一:一次性处理完整集合(推荐)

如果已经收集完所有人物实体,直接一次性筛选出不被其他任何名字包含的完整人名:

def keep_full_names(nameset: set[str]) -> set[str]:
    full_names = set()
    for name in nameset:
        # 检查当前名字是否不被集合中其他任何名字包含
        is_full = True
        for other_name in nameset:
            if name != other_name and name in other_name:
                is_full = False
                break
        if is_full:
            full_names.add(name)
    return full_names

# 测试示例
test_set = {'von der Leyen', 'Meloni', 'Lars Danielsson', 'Lars', 'Giorgia Meloni', 'Ursula von der Leyen', 'Giorgia'}
result = keep_full_names(test_set)
print(result)
# 输出: {'Lars Danielsson', 'Giorgia Meloni', 'Ursula von der Leyen'}

方案二:逐个添加时维护集合

如果需要在逐个提取实体时维护集合,可以修改添加逻辑:

def add_full_name(reference: str, nameset: set[str]) -> set[str]:
    # 先移除集合中所有被当前reference包含的短名字
    to_remove = {name for name in nameset if name in reference}
    nameset.difference_update(to_remove)
    
    # 检查当前reference是否被集合中已有长名字包含,没包含才添加
    for name in nameset:
        if reference in name:
            return nameset
    nameset.add(reference)
    return nameset

# 测试示例
nameset = set()
nameset = add_full_name("von der Leyen", nameset)
nameset = add_full_name("Meloni", nameset)
nameset = add_full_name("Lars Danielsson", nameset)
nameset = add_full_name("Lars", nameset)
nameset = add_full_name("Giorgia Meloni", nameset)
nameset = add_full_name("Ursula von der Leyen", nameset)
nameset = add_full_name("Giorgia", nameset)

print(nameset)
# 输出: {'Lars Danielsson', 'Giorgia Meloni', 'Ursula von der Leyen'}

逻辑说明

  • 方案一通过双重遍历,筛选出所有不被其他名字包含的条目,这些就是最完整的人名,适合批量处理场景。
  • 方案二在每次添加新名字时,先清理集合中的对应短简称,再判断新名字是否需要保留,适合实时添加的场景。

内容的提问来源于stack exchange,提问作者Robert Alexander

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:50:21