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函数存在几个关键逻辑漏洞:
- 判断逻辑不完整:只处理了新传入的短名字,没处理新传入长名字时需要移除对应短简称的情况。
- 冗余操作:
nameset.add(name)完全多余,因为name本来就在集合里。 - 未覆盖反向包含场景:当新传入的长名字包含集合里的短名字时,没有移除那些短名字。
修正方案
方案一:一次性处理完整集合(推荐)
如果已经收集完所有人物实体,直接一次性筛选出不被其他任何名字包含的完整人名:
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
相关产品推荐
相关产品推荐

