Как сделать сравнение строк без учета регистра в Python?

Каков наилучший способ сделать нечувствительное к строкам сравнение строк в Python?

Я хотел бы инкапсулировать сравнение регулярных строк в строку репозитория, используя очень простой и питонический путь. Я также хотел бы иметь возможность искать значения в dict, хэшированные строками, использующими регулярные строки python. Очень благодарен за совет.

10 Solutions collect form web for “Как сделать сравнение строк без учета регистра в Python?”

Предполагая строки ASCII:

string1 = 'Hello' string2 = 'hello' if string1.lower() == string2.lower(): print "The strings are the same (case insensitive)" else: print "The strings are not the same (case insensitive)" 

Сравнение строки в нечувствительном к регистру образом кажется чем-то тривиальным, но это не так. Я буду использовать Python 3, так как Python 2 здесь недостаточно развит.

Первое, что следует отметить, – это то, что конверсии case-remove в unicode не являются тривиальными. Существует текст, для которого text.lower() != text.upper().lower() , например "ß" :

 "ß".lower() #>>> 'ß' "ß".upper().lower() #>>> 'ss' 

Но скажем, вы хотели без "BUSSE" сравнений "BUSSE" и "Buße" . Черт, вы, вероятно, также хотите сравнить "BUSSE" и "BUẞE" равными – это более новая форма капитала. Рекомендуемым способом является использование casefold :

 help(str.casefold) #>>> Help on method_descriptor: #>>> #>>> casefold(...) #>>> S.casefold() -> str #>>> #>>> Return a version of S suitable for caseless comparisons. #>>> 

Не используйте только lower . Если casefold недоступен, выполнение .upper().lower() помогает (но только несколько).

Тогда вы должны рассмотреть акценты. Если ваш рендерер шрифта хорош, вы, вероятно, думаете "ê" == "ê" – но это не так:

 "ê" == "ê" #>>> False 

Это потому, что они на самом деле

 import unicodedata [unicodedata.name(char) for char in "ê"] #>>> ['LATIN SMALL LETTER E WITH CIRCUMFLEX'] [unicodedata.name(char) for char in "ê"] #>>> ['LATIN SMALL LETTER E', 'COMBINING CIRCUMFLEX ACCENT'] 

Самый простой способ справиться с этим – unicodedata.normalize . Вероятно, вы хотите использовать нормализацию NFKD , но не стесняйтесь проверить документацию. Тогда

 unicodedata.normalize("NFKD", "ê") == unicodedata.normalize("NFKD", "ê") #>>> True 

Чтобы закончить, здесь это выражается в функциях:

 import unicodedata def normalize_caseless(text): return unicodedata.normalize("NFKD", text.casefold()) def caseless_equal(left, right): return normalize_caseless(left) == normalize_caseless(right) 

Используя Python 2, вызывая .lower() для каждой строки или Unicode-объекта …

 string1.lower() == string2.lower() 

… будет работать большую часть времени, но на самом деле не работает в ситуациях, описанных @tchrist.

Предположим, у нас есть файл с названием unicode.txt содержащий две строки Σίσυφος и ΣΊΣΥΦΟΣ . С Python 2:

 >>> utf8_bytes = open("unicode.txt", 'r').read() >>> print repr(utf8_bytes) '\xce\xa3\xce\xaf\xcf\x83\xcf\x85\xcf\x86\xce\xbf\xcf\x82\n\xce\xa3\xce\x8a\xce\xa3\xce\xa5\xce\xa6\xce\x9f\xce\xa3\n' >>> u = utf8_bytes.decode('utf8') >>> print u Σίσυφος ΣΊΣΥΦΟΣ >>> first, second = u.splitlines() >>> print first.lower() σίσυφος >>> print second.lower() σίσυφοσ >>> first.lower() == second.lower() False >>> first.upper() == second.upper() True 

Символ Σ имеет две формы в нижнем регистре, ς и σ, а .lower() не поможет сравнивать их без .lower() регистра.

Однако, начиная с Python 3, все три формы будут разрешены для ς, и вызов lower () для обеих строк будет работать правильно:

 >>> s = open('unicode.txt', encoding='utf8').read() >>> print(s) Σίσυφος ΣΊΣΥΦΟΣ >>> first, second = s.splitlines() >>> print(first.lower()) σίσυφος >>> print(second.lower()) σίσυφος >>> first.lower() == second.lower() True >>> first.upper() == second.upper() True 

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

(Для справки, Python 2.7.3 и Python 3.3.0b1 показаны в распечатках интерпретатора выше).

Раздел 3.13 стандарта Unicode определяет алгоритмы для сопоставления без содержания.

X.casefold() == Y.casefold() в Python 3 реализует «стандартное сопоставление без содержания» (D144).

Casefolding не сохраняет нормализацию строк во всех случаях, и поэтому необходимо выполнить нормализацию ( 'å' vs. 'å' ). D145 вводит «каноническое несоответствие без содержания»:

 import unicodedata def NFD(text): return unicodedata.normalize('NFD', text) def canonical_caseless(text): return NFD(NFD(text).casefold()) 

NFD() вызывается дважды для очень редких краевых случаев с символом U + 0345.

Пример:

 >>> 'å'.casefold() == 'å'.casefold() False >>> canonical_caseless('å') == canonical_caseless('å') True 

Существует также совместимость несоответствующего соответствия (D146) для таких случаев, как '㎒' (U + 3392) и «несоответствие без идентификатора», чтобы упростить и оптимизировать несогласованное сопоставление идентификаторов .

Как насчет конвертации в нижний регистр? вы можете использовать string.lower() .

Я видел это решение здесь, используя regex .

 import re if re.search('mandy', 'Mandy Pande', re.IGNORECASE): # is True 

Он отлично работает с акцентами

 In [42]: if re.search("ê","ê", re.IGNORECASE): ....: print(1) ....: 1 

Однако он не работает с символами Unicode без учета регистра. Спасибо @Rhymoid за указание на то, что, как я понял, ему нужен точный символ, так как это правда. Вывод выглядит следующим образом:

 In [36]: "ß".lower() Out[36]: 'ß' In [37]: "ß".upper() Out[37]: 'SS' In [38]: "ß".upper().lower() Out[38]: 'ss' In [39]: if re.search("ß","ßß", re.IGNORECASE): ....: print(1) ....: 1 In [40]: if re.search("SS","ßß", re.IGNORECASE): ....: print(1) ....: In [41]: if re.search("ß","SS", re.IGNORECASE): ....: print(1) ....: 

Обычный подход заключается в том, чтобы заглавные строки или нижний регистр для поиска и сравнения. Например:

 >>> "hello".upper() == "HELLO".upper() True >>> 
 def insenStringCompare(s1, s2): """ Method that takes two strings and returns True or False, based on if they are equal, regardless of case.""" try: return s1.lower() == s2.lower() except AttributeError: print "Please only pass strings into this method." print "You passed a %s and %s" % (s1.__class__, s2.__class__) 

Если у вас есть списки со строками, и вы хотите сравнить строки в другом списке с регистром без учета. Вот мое решение.

 list1 = map(lambda each:each.lower(), list1) list2 = map(lambda each:each.lower(), list2) 

После этого вы можете легко выполнить сравнение строк.

Я использовал это, чтобы выполнить что-то более полезное для сравнения двух строк:

 def strings_iequal(first, second): try: return first.upper() == second.upper() except AttributeError: if not first: if not second: return True 

Обновление : Как отметил геррит , в этом ответе есть некоторые ошибки. Это было много лет назад, и я больше не помню, для чего я его использовал. Я действительно помню, как писал тесты, но насколько они хороши!

  • Python: встроенные функции max / min зависят от порядка параметров
  • Почему {} | | () | str | set | и т. Д. > n равно True в python2.x?
  • Почему сравнение строк в Python с использованием «==» или «is» иногда приводит к другому результату?
  • Есть ли смысл использовать скрипты Bash?
  • Предпочитаемые операторы сравнения Python
  • double equals vs находится в python
  • Python. По умолчанию пользовательские классы имеют методы __cmp __ () и __hash __ ()? Или?
  • десятичное сравнение python
  • Почему Clojure в 10 раз медленнее Python для эквивалентного решения Euler 50?
  • Проверка начала строки с XXXX
  • индивидуальное сравнение для встроенных контейнеров
  • Python - лучший язык программирования в мире.