Python 忽略difflib的大小写。get_close_matches()

Python 忽略difflib的大小写。get_close_matches(),python,difflib,Python,Difflib,如何让difflib.get_close_matches()忽略大小写?我有一本字典,它有一个明确的格式,包括大写字母。但是,测试字符串可能有完全资本化或没有资本化,并且这些应该是等效的。但是,结果需要适当大写,因此我不能使用修改过的词典 import difflib names = ['Acacia koa A.Gray var. latifolia (Benth.) H.St.John', 'Acacia koa A.Gray var. waianaeensis H.St.John

如何让difflib.get_close_matches()忽略大小写?我有一本字典,它有一个明确的格式,包括大写字母。但是,测试字符串可能有完全资本化或没有资本化,并且这些应该是等效的。但是,结果需要适当大写,因此我不能使用修改过的词典

import difflib

names = ['Acacia koa A.Gray var. latifolia (Benth.) H.St.John',
    'Acacia koa A.Gray var. waianaeensis H.St.John',
    'Acacia koaia Hillebr.',
    'Acacia kochii W.Fitzg. ex Ewart & Jean White',
    'Acacia kochii W.Fitzg.']
s = 'Acacia kochi W.Fitzg.'

# base case: proper capitalisation
print(difflib.get_close_matches(s,names,1,0.9))

# this should be equivalent from the perspective of my program
print(difflib.get_close_matches(s.upper(),names,1,0.9))

# this won't work because of the dictionary formatting
print(difflib.get_close_matches(s.upper().capitalize(),names,1,0.9))
输出:

['Acacia kochii W.Fitzg.']
[]
[]
['Acacia kochii W.Fitzg.', 'Acacia kochii W.Fitzg.']
工作代码:

根据Hugh Bothwell的回答,我对代码进行了如下修改,以获得一个有效的解决方案(当返回多个结果时,该解决方案也应该有效):

输出:

['Acacia kochii W.Fitzg.']
[]
[]
['Acacia kochii W.Fitzg.', 'Acacia kochii W.Fitzg.']

我看不到任何快速的方法来进行区分大小写的比较

快速而肮脏的解决方案似乎是

  • 创建一个函数,将字符串转换为某种规范形式(例如:大写、单空格、无标点符号)

  • 使用该函数生成{canonical string:original string}的dict和[canonical string]的列表

  • 运行。根据规范字符串列表获取\u close\u匹配,然后通过dict插入结果以获取原始字符串


在进行了大量搜索之后,我非常惊讶地发现,对于这个显而易见的用例,没有一个简单的预先准备好的答案

唯一的选择似乎是。然而,它依赖于Levenshtein距离,就像Python的
difflib
,它的API不是生产质量。它更晦涩的方法确实不区分大小写,但它没有直接或简单地替换
get\u close\u matches

下面是我能想到的最简单的实现:

import difflib

def get_close_matches_icase(word, possibilities, *args, **kwargs):
    """ Case-insensitive version of difflib.get_close_matches """
    lword = word.lower()
    lpos = {p.lower(): p for p in possibilities}
    lmatches = difflib.get_close_matches(lword, lpos.keys(), *args, **kwargs)
    return [lpos[m] for m in lmatches]

@加托皮奇的想法是正确的,但问题是,可能有许多字符串只是大小写不同。我们当然希望他们都在我们的结果中,而不仅仅是其中一个

以下自适应可以做到这一点:

def get_close_matches_icase(word, possibilities, *args, **kwargs):
    """ Case-insensitive version of difflib.get_close_matches """
    lword = word.lower()
    lpos = {}
    for p in possibilities:
        if p.lower() not in lpos:
            lpos[p.lower()] = [p]
        else:
            lpos[p.lower()].append(p)
    lmatches = difflib.get_close_matches(lword, lpos.keys(), *args, **kwargs)
    ret = [lpos[m] for m in lmatches]
    ret = itertools.chain.from_iterable(ret)
    return set(ret)

很抱歉重新启动一篇旧文章,但我觉得这很有趣。对于最终的搜索产品,我正在阅读代码,您似乎不需要s1和第一个结果列表。对吗?看起来这个算法在没有这些行的情况下会产生你想要的结果。@TylerRussell这是正确的。目的是验证搜索词的资本化不会影响结果。用s1搜索和s2搜索得到的结果相同,这表明该算法是有效的。通常,您只会使用一个搜索词。