web-dev-qa-db-ja.com

大文字と小文字を区別しない 'in'-Python

表現を使うのが大好き

if 'MICHAEL89' in USERNAMES:
    ...

ここで、USERNAMESはリストです


大文字と小文字を区別しないアイテムを一致させる方法はありますか、またはカスタムメソッドを使用する必要がありますか?このために余分なコードを書く必要があるかどうか疑問に思っています。

みんなありがとう!

133
RadiantHex
if 'MICHAEL89' in (name.upper() for name in USERNAMES):
    ...

代わりに:

if 'MICHAEL89' in map(str.upper, USERNAMES):
    ...

または、はい、カスタムメソッドを作成できます。

159
nmichaels

wrapperを作成するので、非侵襲的になります。最小限、例えば...:

class CaseInsensitively(object):
    def __init__(self, s):
        self.__s = s.lower()
    def __hash__(self):
        return hash(self.__s)
    def __eq__(self, other):
        # ensure proper comparison between instances of this class
        try:
           other = other.__s
        except (TypeError, AttributeError):
          try:
             other = other.lower()
          except:
             pass
        return self.__s == other

これで、if CaseInsensitively('MICHAEL89') in whatever:は必要に応じて動作するはずです(右側がリスト、辞書、またはセットであるかどうか)。 (文字列を含めるために同様の結果を得るには、さらに労力が必要になる場合があり、unicodeなどが関係する場合には警告を回避します)。

19
Alex Martelli

通常、(少なくともoopでは)目的の動作をするようにオブジェクトを形作ります。 name in USERNAMESは大文字と小文字を区別しないため、USERNAMESは変更する必要があります。

class NameList(object):
    def __init__(self, names):
        self.names = names

    def __contains__(self, name): # implements `in`
        return name.lower() in (n.lower() for n in self.names)

    def add(self, name):
        self.names.append(name)

# now this works
usernames = NameList(USERNAMES)
print someone in usernames

これの素晴らしいところは、クラス外のコードを変更することなく、多くの改善への道を開くことです。たとえば、self.namesをセットに変更してルックアップを高速化したり、(n.lower() for n in self.names)を1回だけ計算してクラスなどに保存したりできます。

10
Jochen Ritzel

余分なコードを書く必要があると思います。例えば:

if 'MICHAEL89' in map(lambda name: name.upper(), USERNAMES):
   ...

この場合、USERNAMESのすべてのエントリが大文字に変換された新しいリストを作成し、この新しいリストと比較します。

更新

@ viraptor が示すように、mapの代わりにジェネレーターを使用することをお勧めします。 @ Nathonanswer を参照してください。

6
Manoj Govindan

1つの方法を次に示します。

if string1.lower() in string2.lower(): 
    ...

これが機能するには、string1およびstring2オブジェクトの両方がstring型である必要があります。

6
User

str.casefoldは、大文字と小文字を区別しない文字列照合に推奨されます。 @ nmichaelsの解 は簡単に適応できます。

次のいずれかを使用します。

if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):

または:

if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):

docs

ケースフォールディングは小文字化に似ていますが、文字列内のすべての大文字と小文字の区別を削除することを目的としているため、より積極的です。たとえば、ドイツ語の小文字「ß」は「ss」と同等です。既に小文字なので、lower()は 'ß'に対して何もしません。 casefold()は「ss」に変換します。

5
jpp

できる

matcher = re.compile('MICHAEL89', re.IGNORECASE)
filter(matcher.match, USERNAMES) 

更新:少し遊んで、あなたがより良い短絡型のアプローチを得ることができると考えています

matcher = re.compile('MICHAEL89', re.IGNORECASE)
if any( ifilter( matcher.match, USERNAMES ) ):
    #your code here

ifilter関数は、Pythonで私のお気に入りのモジュールの1つであるitertoolsからのものです。ジェネレータよりも高速ですが、呼び出されたときにリストの次のアイテムのみを作成します。

4
wheaties

私の5(間違った)セント

"" .join(['A'])。lower()の 'a'

更新

@jppに完全に同意します。悪い習慣の例として私は続けます:(

0
GBrian