13

大文字と小文字を区別しないように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.']
[]
[]

作業コード:

Hugh Bothwellの回答に基づいて、次のようにコードを変更して、機能するソリューションを取得しました(これは、複数の結果が返された場合にも機能するはずです)。

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.']
test = {n.lower():n for n in names}    
s1 = 'Acacia kochi W.Fitzg.'   # base case
s2 = 'ACACIA KOCHI W.FITZG.'   # test case

results = [test[r] for r in difflib.get_close_matches(s1.lower(),test,1,0.9)]
results += [test[r] for r in difflib.get_close_matches(s2.lower(),test,1,0.9)]
print results

出力:

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

3 に答える 3

13

difflibで大文字と小文字を区別しない比較を行う簡単な方法はわかりません。

迅速で汚い解決策は

  • 文字列を標準形に変換する関数を作成します(例:大文字、シングルスペース、句読点なし)

  • その関数を使用して、{正規文字列:元の文字列}の辞書と[正規文字列]のリストを作成します

  • canonical-stringリストに対して.get_close_matchesを実行し、結果をdictに接続して、元の文字列を元に戻します。

于 2012-07-08T17:06:28.913 に答える
4

何度も検索した後、この明らかなユースケースに対する簡単な事前に用意された答えがないことに悲しいことに驚いています。

唯一の選択肢は「FuzzyWuzzy」ライブラリのようです。それでも、Pythonと同じようにLevenshtein Distanceに依存しておりdifflib、そのAPIは本番品質ではありません。そのよりあいまいな方法は、実際には大文字と小文字を区別しませんが、の直接または単純な置き換えは提供しませんget_close_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]
于 2019-04-09T10:30:05.097 に答える
1

@gatopeichは正しい考えを持っていましたが、問題は、大文字と小文字だけが異なる文字列が多数ある可能性があることです。そのうちの1つだけでなく、すべてを結果に含めることをお勧めします。

次の適応はこれを行うことができます:

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)
于 2019-12-21T19:26:28.323 に答える