Без учета регистра 'in' - Python

Я люблю использовать выражение

if 'MICHAEL89' in USERNAMES:
    ...

, где USERNAMES - список


Есть ли способ сопоставить элементы с нечувствительностью к регистру или мне нужно использовать пользовательский метод? Просто интересно, есть ли необходимость писать дополнительный код для этого.

Спасибо всем!

вопрос задан 2.09.2010
RadiantHex
9476 репутация

7 ответов


  • 137 рейтинг
    if 'MICHAEL89' in (name.upper() for name in USERNAMES):
        ...
    

    в качестве альтернативы:

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

    Или, да, вы можете сделать пользовательский метод.

    ответ дан nmichaels, с репутацией 35372, 2.09.2010
  • 15 рейтинг

    Я бы сделал оболочку , чтобы вы могли быть неинвазивным. Минимально, например. , , :

    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 и т. Д.).

    ответ дан Alex Martelli, с репутацией 602466, 2.09.2010
  • 9 рейтинг

    Обычно (по крайней мере, в 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) только один раз и сохранить его в классе и так далее. , ,

    ответ дан Jochen Ritzel, с репутацией 73924, 2.09.2010
  • 6 рейтинг

    Я думаю, что вы должны написать дополнительный код. Например:

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

    В этом случае мы формируем новый список со всеми записями в USERNAMES, преобразованными в верхний регистр и затем сравниваем с этим новым списком.

    Обновление

    Как говорит @viraptor , еще лучше использовать генератор вместо map. См. @Nathon 's ответ .

    ответ дан Manoj Govindan, с репутацией 46632, 2.09.2010
  • 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. Это быстрее, чем генератор, но создает только следующий элемент списка при вызове.

    ответ дан wheaties, с репутацией 29605, 2.09.2010
  • 4 рейтинг

    Вот один из способов:

    if string1.lower() in string2.lower(): 
        ...
    
    ответ дан User, с репутацией 7337, 1.08.2014
  • 1 рейтинг

    str.casefold рекомендуется для сопоставления строк без учета регистра. Решение @ nmichaels можно легко адаптировать.

    Использовать либо:

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

    или

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

    Согласно документам :

    Casefolding похож на нижний регистр, но более агрессивен, потому что предназначен для удаления всех различий в строке. Например, немецкая строчная буква «ß» эквивалентна «ss». Так как это уже строчные, lower() не будет ничего делать с 'ß'; casefold() преобразует его в «сс».

    ответ дан jpp, с репутацией 67130, 10.08.2018