表現が大好き
if 'MICHAEL89' in USERNAMES:
...
どこUSERNAMES
リストです。
大文字と小文字を区別せずにアイテムを一致させる方法はありますか、またはカスタムメソッドを使用する必要がありますか?これのために追加のコードを書く必要があるかどうか疑問に思っています。
表現が大好き
if 'MICHAEL89' in USERNAMES:
...
どこUSERNAMES
リストです。
大文字と小文字を区別せずにアイテムを一致させる方法はありますか、またはカスタムメソッドを使用する必要がありますか?これのために追加のコードを書く必要があるかどうか疑問に思っています。
回答:
username = 'MICHAEL89'
if username.upper() in (name.upper() for name in USERNAMES):
...
または:
if username.upper() in map(str.upper, USERNAMES):
...
または、はい、カスタムメソッドを作成できます。
[...]
リスト全体を作成します。(name.upper() for name in USERNAMES)
ジェネレータと必要な文字列を一度に1つだけ作成します。この操作を頻繁に行うと、メモリを大幅に節約できます。(毎回チェックするために再利用する小文字のユーザー名のリストを単に作成した場合、さらに節約できます)
非侵襲的になるようにラッパーを作ります。少なくとも、例えば...:
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:
必要に応じて動作するはずです(右側がリスト、dict、セットのいずれであるか)。(文字列を含めるために同様の結果を得るには、より多くの労力が必要になる場合があります。一部のケースでは警告を回避するunicode
など)。
CaseInsensitively('MICHAEL89') in {CaseInsensitively('Michael89'):True}
それが機能するためには、おそらく「必要に応じて振る舞う」には該当しないでしょう。
etc.
必要です(私の回答の短い部分と「より多くの努力が必要」部分)。
通常、(少なくとも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)
一度だけ計算してクラスに保存したりすることができます。
str.casefold
大文字と小文字を区別しない文字列の照合には推奨されます。@nmichaelsのソリューションは簡単に適応できます。
次のいずれかを使用します。
if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):
または:
if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):
あたりとして、ドキュメント:
大文字と小文字の区別は小文字に似ていますが、文字列内のすべての大文字と小文字の区別を取り除くことを目的としているため、より積極的です。たとえば、ドイツ語の小文字「ß」は「ss」と同等です。すでに小文字なので
lower()
、 'ß'には何もしません。casefold()
「ss」に変換します。
これが1つの方法です。
if string1.lower() in string2.lower():
...
これが機能するには、string1
とstring2
オブジェクトの両方がタイプである必要がありstring
ます。
あなたはいくつかの追加のコードを書く必要があると思います。例えば:
if 'MICHAEL89' in map(lambda name: name.upper(), USERNAMES):
...
この場合、すべてのエントリがUSERNAMES
大文字に変換された新しいリストを作成し、この新しいリストと比較します。
更新
以下のよう@viraptorは言う、代わりの発電機を使用することでも良いですmap
。@Nathonの回答を参照してください。
itertools
functionを使用できますimap
。ジェネレーターよりもはるかに高速ですが、同じ目標を達成します。
あなたができる
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
この関数は、itertoolsからPythonの内の私のお気に入りのモジュールの一つです。ジェネレーターよりも高速ですが、呼び出されたときにリストの次の項目のみを作成します。
リストの代わりに辞書にこれが必要でしたが、Jochenソリューションがそのケースで最もエレガントだったので、少し修正しました:
class CaseInsensitiveDict(dict):
''' requests special dicts are case insensitive when using the in operator,
this implements a similar behaviour'''
def __contains__(self, name): # implements `in`
return name.casefold() in (n.casefold() for n in self.keys())
今、あなたはそのように辞書を変換してUSERNAMESDICT = CaseInsensitiveDict(USERNAMESDICT)
使用することができますif 'MICHAEL89' in USERNAMESDICT:
if 'CaseFudge'.lower() in [x.lower() for x in list]