不区分大小写'in' - Python

时间:2010-09-02 13:56:30

标签: python list case-insensitive

我喜欢使用表达式

if 'MICHAEL89' in USERNAMES:
    ...

其中USERNAMES是一个列表


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

感谢大家!

10 个答案:

答案 0 :(得分:149)

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

可替换地:

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

或者,是的,您可以制作自定义方法。

答案 1 :(得分:17)

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

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的情况下避免警告等。)

答案 2 :(得分:10)

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

答案 3 :(得分:6)

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

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

在这种情况下,我们正在形成一个新列表,其中USERNAMES中的所有条目都转换为大写,然后与此新列表进行比较。

更新

正如@viraptor所说,使用生成器代替map更好。请参阅@Nathonanswer

答案 4 :(得分:5)

以这种方式:

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

为此,string1string2个对象的类型必须为string

答案 5 :(得分:4)

你可以做到

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

答案 6 :(得分:4)

建议使用

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”。

答案 7 :(得分:0)

我的5分(错误)

  

'a'in“” .join(['A'])。lower()

更新

哦,完全同意@jpp,我将举一个不良做法的例子:(

答案 8 :(得分:0)

我需要一个字典而不是列表,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:

答案 9 :(得分:0)

要一行完成,这就是我所做的:

git rebase -X ours

虽然我没有及时进行测试。我不确定它的速度/效率。