Python中的"in"操作符如何比较不同长度单词的字符串?

4
我正在处理一个可能存在重复条目的姓名数据库,并试图确定是否有两个相同的条目,但不幸的是,格式不太理想,有些条目将名字、中间名、姓氏或娘家姓合并为一个字符串,而有些则只有名字和姓氏。
我需要一种方法来查看例如'John Marvulli' 是否与 'John Michael Marvulli' 匹配,并能对这些匹配执行操作。然而,如果您尝试:
>>> 'John Marvulli' in 'John Michael Marvulli'
False

它返回False。有没有一种简便的方法来比较两个字符串,以查看一个名称是否包含在另一个名称中?

1
使用正则表达式(不幸的是我需要一些时间来找出您需要的确切正则表达式,但正则表达式是您的好朋友) - El Hocko
1
快速回答并不一定是最好的。你在Stackoverflow上还是新手,你会发现更好的答案通常需要更多的时间才能发布。 - eyquem
阅读“格式不太理想”,我认为数据库中可能有拼写错误。我的答案检测到了“John Michael Marvulli”和“John Michael Marvvulli”的匹配。通过“SequenceMatcher”的方法“ratio()”计算的比率条件使得程序能够检测到“John Michael Marvulli”和“John Michael Marvvulli”的匹配,但对于“Peter Michael Marvulli”和“John Michael Marvulli”则没有反应。 - eyquem
是的,我正在测试并注意到我缺少了一些。 - Joel Smith
那么,你的结论是什么? - eyquem
3个回答

7

您需要拆分字符串并查找单个单词:

>>> all(x in 'John Michael Marvulli'.split() for x in 'John Marvulli'.split())
True

我会选择:set('John Marvulli'.split()).issubset('John Michael Marvulli'.split()) - Bakuriu
如果我想要相反的操作,比如返回所有名字不在列表中的用户,该怎么办? - Joel Smith
在谓词前面加上 not。或者你也可以使用 itertools.ifilterfalse - Bakuriu
@Joel Smith @Wooble “all(x in 'John Marvulli'.split() for x in 'John Michael Marvulli'.split())” 的结果是“False”,尽管它们匹配。因此,有必要测试这两个顺序。 - eyquem
@eyquem:确实;我回答了OP所问的问题,而不是试图猜测他真正想解决的XY问题。 - Wooble
@Wooble,你错误地使用了“XY问题”的短语,原因有两个:1)在这个短语中,X是一个问题,Y是一种试图解决的方法,而XY问题本身则是认为Y可能是解决X的方法,因此询问Y而不是X。因此,“XY问题”不是某人可能拥有的所谓“真实”问题,而是他实际存在的问题。请参见(http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)**2)**目前,Joel没有XY问题,因为他公开了自己的实际问题,并意识到使用“in”不能构成解决方案。 - eyquem

2

我最近发现了 difflib 模块的强大功能。
我认为这将对你有所帮助:

import difflib

datab = ['Pnk Flooyd', 'John Marvulli',
         'Ld Zeppelin', 'John Michael Marvulli',
         'Led Zepelin', 'Beetles', 'Pink Fl',
         'Beatlez', 'Beatles', 'Poonk LLoyds',
         'Pook Loyds']
print datab
print


li = []
s = difflib.SequenceMatcher()

def yield_ratios(s,iterable):
    for x in iterable:
        s.set_seq1(x)
        yield s.ratio()

for text_item in datab:
    s.set_seq2(text_item)
    for gathered in li:
        if any(r>0.45 for r in yield_ratios(s,gathered)):
            gathered.append(text_item)
            break
    else:
        li.append([text_item])


for el in li:
    print el

结果

['Pnk Flooyd', 'Pink Fl', 'Poonk LLoyds', 'Pook Loyds']
['John Marvulli', 'John Michael Marvulli']
['Ld Zeppelin', 'Led Zepelin']
['Beetles', 'Beatlez', 'Beatles']

1
我测试了,答案是肯定的。我列出了字符串“JOHN MARVULLI”、“JOHN MARVULLi”、“JOHN MARVULli”、“JOHN MARVUlli”、“JOHN MARVulli”、“JOHN MARvulli”、“JOHN MArvulli”、“JOHN Marvulli”、“JOHN marvulli”、“JOHn marvulli”、“JOhn marvulli”、“John marvulli”、“john marvulli””相对于“john marvulli”的比率,并给出递增的数字“0.077 0.154 0.231 0.308 0.385 0.462 0.538 0.615 0.692 0.769 0.846 0.923 1.000”。 - eyquem
@Joel Smith,不好意思,我遇到了英语或逻辑上的问题:它是区分大小写的,因为SequenceMatcher实例在'JOHN MARVulli''JOHn marvulli'之间看到了差异。- 那么,现在你解决了你的问题吗?我的解决方案或其他方案是否帮助了你?还有什么问题没有解决吗? - eyquem
@Joel Smith,由于我不是以英语为母语的人,所以我去了(http://www.thefreedictionary.com/tear+apart)学习"to tear apart"的意思。据说它的意思是_"表达完全负面的观点"_。那么你的句子不是矛盾的吗? - eyquem
@Joel Smith 我提醒你注意以下重点:在 yield_ratios() 函数中,我首先使用了 s.set_seq2(text_item) ,然后再算法性地使用 s.set_seq1(x)。这是因为:“SequenceMatcher计算并缓存有关第二个序列的详细信息,因此,如果您想将一个序列与多个序列进行比较,请使用set_seq2()一次设置常用序列,并针对每个其他序列重复调用 set_seq1()。”,摘自文档。 - eyquem
我并不是指在那个意义上去批判它。我的意思是我正在尝试理解它的工作原理。 - Joel Smith
显示剩余3条评论

0
import re

n1 = "john Miller"
n1 = "john   Miller"

n2 = "johnas Miller"

n3 = "john doe Miller"
n4 = "john doe paul Miller"


regex = "john \\s*(\\w*\\s*)*\\s* Miller"
compiled=re.compile(regex)

print(compiled.search(n1)==None)
print(compiled.search(n2)==None)
print(compiled.search(n3)==None)
print(compiled.search(n4)==None)

'''
output:


False
True
False
False
'''

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接