不区分大小写的字符串比较

以不区分大小写的方式比较字符串似乎是微不足道的,但事实并非如此。本节仅考虑 unicode 字符串(Python 3 中的默认值)。请注意,Python 2 可能具有相对于 Python 3 的微妙弱点 - 后者的 unicode 处理要完整得多。

首先要注意的是,在 unicode 中删除大小写的转换并非易事。有 text.lower() != text.upper().lower() 的文字,如 ß

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

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

但是,让我们说你想无比地比较 BUSSEBuße。哎呀,你可能也想比较 BUSSEBUẞE 相等 - 这是更新的资本形式。推荐的方法是使用 casefold

Python 3.x >= 3.3

>>> 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)