Сравнение строк без учета регистра

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

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

 >>> "ß".lower()
'ß'

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

 

Но предположим, что вы хотели регистронезависмо сравнивать "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)