不区分大小写'in'

我喜欢用这个表达

if 'MICHAEL89' in USERNAMES:
...

其中USERNAMES是一个列表。


是否有任何方法来匹配不区分大小写的项目,或者我需要使用自定义方法?只是想知道是否需要为此编写额外的代码。

171050 次浏览
username = 'MICHAEL89'
if username.upper() in (name.upper() for name in USERNAMES):
...

另外:

if username.upper() in map(str.upper, USERNAMES):
...

或者,是的,您可以创建一个自定义方法。

我认为你需要写一些额外的代码。例如:

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

在本例中,我们将形成一个新列表,其中USERNAMES中的所有条目都转换为大写,然后与这个新列表进行比较。

更新

正如@viraptor所说,使用生成器比使用map更好。参见@Nathon回答

你可以这样做

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中我最喜欢的模块之一。它比生成器快,但只在调用时创建列表的下一项。

我会做一个包装器,这样你就可以是非侵入性的。最低限度,例如……:

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等的警告)。

通常(至少在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)并将其存储在类中,等等……

这里有一种方法:

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

为此,string1string2对象都必须是string类型。

str.casefold建议用于不区分大小写的字符串匹配。@nmichaels的解决方案可以被简单地改编。

使用:

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

或者:

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

根据文档:

casefold类似于小写,但更激进,因为它 用于删除字符串中的所有大小写区别。例如, 德语小写字母“ß”相当于“ss”。因为它是 已经小写,lower()不会对'ß'做任何事情;casefold()

我的5美分(错误的)

"".join([' a']).lower()

更新

哎呦,完全同意@jpp,我会把它作为一个糟糕做法的例子:(

我需要这个字典而不是列表,杨晨的解决方案是最优雅的情况下,所以我修改了一点:

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 any(([True if 'MICHAEL89' in username.upper() else False for username in USERNAMES])):
print('username exists in list')

不过我并没有在时间上进行测试。我不确定它有多快/有效率。

来自本教程的例子:

list1 = ["Apple", "Lenovo", "HP", "Samsung", "ASUS"]


s = "lenovo"
s_lower = s.lower()


res = s_lower in (string.lower() for string in list1)


print(res)