Python 不区分大小写的“in”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3627784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:59:53  来源:igfitidea点击:

Case insensitive 'in'

pythonstringlistcase-insensitive

提问by RadiantHex

I love using the expression

我喜欢用这个表达

if 'MICHAEL89' in USERNAMES:
    ...

where USERNAMESis a list.

USERNAMES列表在哪里。



Is there any way to match items with case insensitivity or do I need to use a custom method? Just wondering if there is a need to write extra code for this.

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

回答by nmichaels

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

Alternatively:

或者:

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

Or, yes, you can make a custom method.

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

回答by Manoj Govindan

I think you have to write some extra code. For example:

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

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

In this case we are forming a new list with all entries in USERNAMESconverted to upper case and then comparing against this new list.

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

Update

更新

As @viraptorsays, it is even better to use a generator instead of map. See @Nathon's answer.

正如@viraptor所说,使用生成器而不是map. 请参阅@Nathon回答

回答by wheaties

You could do

你可以做

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

Update: played around a bit and am thinking you could get a better short-circuit type approach using

更新:玩了一下,我想你可以使用更好的短路类型方法

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

The ifilterfunction is from itertools, one of my favorite modules within Python. It's faster than a generator but only creates the next item of the list when called upon.

ifilter函数来自 itertools,这是我最喜欢的 Python 模块之一。它比生成器快,但仅在调用时创建列表的下一项。

回答by Alex Martelli

I would make a wrapperso you can be non-invasive. Minimally, for example...:

我会做一个包装,这样你就可以是非侵入性的。至少,例如...:

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

Now, if CaseInsensitively('MICHAEL89') in whatever:should behave as required (whether the right-hand side is a list, dict, or set). (It may require more effort to achieve similar results for string inclusion, avoid warnings in some cases involving unicode, etc).

现在,if CaseInsensitively('MICHAEL89') in whatever:应该按要求运行(无论右侧是列表、字典还是集合)。(可能需要付出更多努力才能获得类似的字符串包含结果,避免在某些涉及 的情况下发出警告unicode等)。

回答by Jochen Ritzel

Usually (in oop at least) you shape your object to behave the way you want. name in USERNAMESis not case insensitive, so USERNAMESneeds to change:

通常(至少在 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

The great thing about this is that it opens the path for many improvements, without having to change any code outside the class. For example, you could change the self.namesto a set for faster lookups, or compute the (n.lower() for n in self.names)only once and store it on the class and so on ...

这样做的好处在于,它为许多改进开辟了道路,而无需更改类之外的任何代码。例如,您可以将 the 更改self.names为一个集合以加快查找速度,或者(n.lower() for n in self.names)只计算一次并将其存储在类中等等......

回答by User

Here's one way:

这是一种方法:

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

For this to work, both string1and string2objects must be of type string.

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

回答by jpp

str.casefoldis recommended for case-insensitive string matching. @nmichaels's solutioncan trivially be adapted.

str.casefold推荐用于不区分大小写的字符串匹配。@nmichaels 的解决方案可以轻松适应。

Use either:

使用:

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

Or:

或者:

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

As per the docs:

根据文档

Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string. For example, the German lowercase letter '?' is equivalent to "ss". Since it is already lowercase, lower()would do nothing to '?'; casefold()converts it to "ss".

Casefolding 类似于小写,但更具侵略性,因为它旨在消除字符串中的所有大小写区别。例如,德语小写字母“?” 相当于“ss”。既然已经是小写了,lower()就不会对'?'做任何处理;casefold()将其转换为“ss”。

回答by GBrian

My 5 (wrong) cents

我的 5(错误)美分

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

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

UPDATE

更新

Ouch, totally agree @jpp, I'll keep as an example of bad practice :(

哎哟,完全同意@jpp,我会继续作为坏习惯的例子:(

回答by Megarushing

I needed this for a dictionary instead of list, Jochen solution was the most elegant for that case so I modded it a bit:

我需要这个作为字典而不是列表,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())

now you can convert a dictionary like so USERNAMESDICT = CaseInsensitiveDict(USERNAMESDICT)and use if 'MICHAEL89' in USERNAMESDICT:

现在您可以像这样转换字典USERNAMESDICT = CaseInsensitiveDict(USERNAMESDICT)并使用if 'MICHAEL89' in USERNAMESDICT: