【发布时间】:2010-09-02 13:56:30
【问题描述】:
我喜欢使用表达方式
if 'MICHAEL89' in USERNAMES:
...
USERNAMES 是一个列表。
有什么方法可以匹配不区分大小写的项目,还是我需要使用自定义方法?只是想知道是否需要为此编写额外的代码。
【问题讨论】:
标签: python string list case-insensitive
我喜欢使用表达方式
if 'MICHAEL89' in USERNAMES:
...
USERNAMES 是一个列表。
有什么方法可以匹配不区分大小写的项目,还是我需要使用自定义方法?只是想知道是否需要为此编写额外的代码。
【问题讨论】:
标签: python string list case-insensitive
username = 'MICHAEL89'
if username.upper() in (name.upper() for name in USERNAMES):
...
或者:
if username.upper() in map(str.upper, USERNAMES):
...
或者,是的,您可以制作自定义方法。
【讨论】:
if 'CaseFudge'.lower() in [x.lower() for x in list]
[...] 创建整个列表。 (name.upper() for name in USERNAMES) 一次只会创建一个生成器和一个需要的字符串 - 如果您经常执行此操作,则会节省大量内存。 (如果您只是创建一个小写用户名列表,您可以重复使用这些用户名列表来每次检查)
str.casefold 推荐用于不区分大小写的字符串匹配。 @nmichaels's solution 可以轻松适应。
使用任一:
if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):
或者:
if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):
根据docs:
大小写折叠类似于小写,但更具侵略性,因为它 旨在删除字符串中的所有大小写区别。例如, 德语小写字母“ß”相当于“ss”。因为它是 已经小写了,
lower()不会对 'ß' 做任何事情;casefold()将其转换为“ss”。
【讨论】:
我会制作一个包装器,这样您就可以无创。至少,例如...:
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 的情况下出现警告等)。
【讨论】:
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) 并将其存储在类中等等...
【讨论】:
这是一种方法:
if string1.lower() in string2.lower():
...
为此,string1 和 string2 对象都必须是 string 类型。
【讨论】:
你可以的
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 中最喜欢的模块之一。它比生成器快,但只在调用时创建列表的下一项。
【讨论】:
要将它放在一行中,这就是我所做的:
if any(([True if 'MICHAEL89' in username.upper() else False for username in USERNAMES])):
print('username exists in list')
不过,我没有按时间进行测试。我不确定它的速度/效率有多高。
【讨论】:
我的 5(错误)美分
'a' in "".join(['A']).lower()
哎呀,完全同意@jpp,我将作为不良做法的一个例子:(
【讨论】:
'a' in "".join(['AB']).lower() 返回True,而这不是 OP 想要的。
我需要这个作为字典而不是列表,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:
【讨论】: