How do I do a case-insensitive string comparison?

前端 未结 9 2196
无人及你
无人及你 2020-11-21 07:46

How can I do case insensitive string comparison in Python?

I would like to encapsulate comparison of a regular strings to a repository string using in a very simple

相关标签:
9条回答
  • 2020-11-21 08:34

    Comparing strings in a case insensitive way seems trivial, but it's not. I will be using Python 3, since Python 2 is underdeveloped here.

    The first thing to note is that case-removing conversions in Unicode aren't trivial. There is text for which text.lower() != text.upper().lower(), such as "ß":

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

    But let's say you wanted to caselessly compare "BUSSE" and "Buße". Heck, you probably also want to compare "BUSSE" and "BUẞE" equal - that's the newer capital form. The recommended way is to use casefold:

    str.casefold()

    Return a casefolded copy of the string. Casefolded strings may be used for caseless matching.

    Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string. [...]

    Do not just use lower. If casefold is not available, doing .upper().lower() helps (but only somewhat).

    Then you should consider accents. If your font renderer is good, you probably think "ê" == "ê" - but it doesn't:

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

    This is because the accent on the latter is a combining character.

    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']
    

    The simplest way to deal with this is unicodedata.normalize. You probably want to use NFKD normalization, but feel free to check the documentation. Then one does

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

    To finish up, here this is expressed in functions:

    import unicodedata
    
    def normalize_caseless(text):
        return unicodedata.normalize("NFKD", text.casefold())
    
    def caseless_equal(left, right):
        return normalize_caseless(left) == normalize_caseless(right)
    
    0 讨论(0)
  • 2020-11-21 08:36

    Assuming ASCII strings:

    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)")
    
    0 讨论(0)
  • 2020-11-21 08:37

    I saw this solution here using regex.

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

    It works well with accents

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

    However, it doesn't work with unicode characters case-insensitive. Thank you @Rhymoid for pointing out that as my understanding was that it needs the exact symbol, for the case to be true. The output is as follows:

    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)
    ....:
    
    0 讨论(0)
提交回复
热议问题