Ответ 1
if 'MICHAEL89' in (name.upper() for name in USERNAMES):
...
В качестве альтернативы:
if 'MICHAEL89' in map(str.upper, USERNAMES):
...
Или, да, вы можете создать собственный метод.
Мне нравится использовать выражение
if 'MICHAEL89' in USERNAMES:
...
где USERNAMES
- список
Есть ли способ сопоставить элементы с нечувствительностью к регистру или мне нужно использовать собственный метод? Просто интересно, нужно ли писать дополнительный код для этого.
Спасибо всем!
if 'MICHAEL89' in (name.upper() for name in USERNAMES):
...
В качестве альтернативы:
if 'MICHAEL89' in map(str.upper, USERNAMES):
...
Или, да, вы можете создать собственный метод.
Я бы сделал обертку, чтобы вы не были инвазивны. Минимально, например...:
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:
должен вести себя по мере необходимости (есть ли правая часть - список, dict или set). (Может потребоваться больше усилий для достижения аналогичных результатов для включения строк, во избежание предупреждений в некоторых случаях с участием unicode
и т.д.).
Обычно (по крайней мере, по крайней мере) вы формируете свой объект, чтобы вести себя так, как вы хотите. 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 'MICHAEL89' in map(lambda name: name.upper(), USERNAMES):
...
В этом случае мы формируем новый список со всеми элементами в USERNAMES
, преобразованными в верхний регистр, а затем сравниваем с этим новым списком.
Обновить
Как @viraptor говорит, что лучше использовать генератор вместо map
. См. @Nathon .
Вы могли бы сделать
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. Это быстрее, чем генератор, но создает только следующий элемент списка при вызове.
str.casefold
рекомендуется для сопоставления строк без str.casefold
регистра. Решение @nmichaels можно легко адаптировать.
Используйте либо:
if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):
Или же:
if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):
Согласно документам:
Свертывание регистров похоже на нижний регистр, но более агрессивно, потому что оно предназначено для удаления всех различий регистра в строке. Например, немецкая строчная буква "ß" эквивалентна "ss". Так как это уже строчные буквы,
lower()
ничего не будет делать с 'ß';casefold()
преобразует его в "ss".
Здесь один из способов:
if string1.lower() in string2.lower():
...
Чтобы это работало, оба объекта string1
и string2
должны иметь тип string
.
Мои 5 (неправильных) центов
'a' в "".join(['A']). lower()
Ой, полностью согласен @jpp, я приведу пример плохой практики :(