Case insensitive 'in'

Viewed 165274

I love using the expression

if 'MICHAEL89' in USERNAMES:
    ...

where USERNAMES is a list.


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.

11 Answers

str.casefold is recommended for case-insensitive string matching. @nmichaels's solution can trivially be adapted.

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".

To have it in one line, this is what I did:

if any(([True if 'MICHAEL89' in username.upper() else False for username in USERNAMES])):
    print('username exists in list')

I didn't test it time-wise though. I am not sure how fast/efficient it is.

My 5 (wrong) cents

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

UPDATE

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

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

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:

Example from this tutorial:

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

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

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

print(res)
Related