web-dev-qa-db-de.com

Wie führe ich einen String-Vergleich durch, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird?

Wie kann ich in Python Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung vergleichen?

Ich möchte den Vergleich eines regulären Strings mit einem Repository-String auf sehr einfache und pythonische Weise zusammenfassen. Ich möchte auch die Möglichkeit haben, Werte in einem Diktat nachzuschlagen, das von Zeichenfolgen mit regulären Zeichenfolgen python gehasht wurde.

494
Kozyarchuk

Angenommen, ASCII Zeichenfolgen:

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)")
527
Harley Holcombe

Das Vergleichen von Strings in Groß- und Kleinschreibung erscheint trivial, ist es aber nicht. Ich werde Python 3 verwenden, da Python 2 hier unterentwickelt ist.

Als erstes ist zu beachten, dass das Entfernen von Groß- und Kleinschreibung in Unicode nicht trivial ist. Es gibt Text, für den text.lower() != text.upper().lower(), z. B. _"ß"_:

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

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

Angenommen, Sie wollten _"BUSSE"_ und _"Buße"_ ohne Zwischenfälle vergleichen. Zum Teufel, Sie möchten wahrscheinlich auch _"BUSSE"_ und _"BUẞE"_ gleich vergleichen - das ist die neuere Großbuchstabenform. Der empfohlene Weg ist casefold :

str. casefold ()

Geben Sie eine Kopie der Zeichenfolge in Groß- und Kleinschreibung zurück. Casefolded Strings können für das caseless Matching verwendet werden.

Casefolding ähnelt Lowercasing, ist jedoch aggressiver, da alle Fallunterscheidungen in einer Zeichenfolge entfernt werden sollen. [...]

Verwenden Sie nicht nur lower. Wenn casefold nicht verfügbar ist, hilft .upper().lower() (aber nur ein wenig).

Dann sollten Sie Akzente setzen. Wenn Ihr Zeichensatzrenderer gut ist, denken Sie wahrscheinlich _"ê" == "ê"_ - aber das tut es nicht:

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

Dies liegt daran, dass der Akzent auf dem letzteren ein kombinierender Charakter ist.

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

Der einfachste Weg, damit umzugehen, ist unicodedata.normalize . Sie möchten wahrscheinlich NFKD normalization verwenden, können jedoch die Dokumentation lesen. Dann tut man es

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

Abschließend wird dies in Funktionen ausgedrückt:

_import unicodedata

def normalize_caseless(text):
    return unicodedata.normalize("NFKD", text.casefold())

def caseless_equal(left, right):
    return normalize_caseless(left) == normalize_caseless(right)
_
429
Veedrac

Mit Python 2 .lower() für jeden String oder jedes Unicode-Objekt aufrufen ...

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

... wird die meiste Zeit funktionieren, funktioniert aber in der Tat nicht in Situationen, die @tchrist beschrieben hat .

Angenommen, wir haben eine Datei mit dem Namen unicode.txt, die die beiden Zeichenfolgen Σίσυφος und ΣΊΣΥΦΟΣ enthält. Mit 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

Das Zeichen Σ hat zwei Kleinbuchstaben, ς und σ, und .lower() hilft nicht, sie ohne Rücksicht auf die Groß-/Kleinschreibung zu vergleichen.

Ab Python 3 werden jedoch alle drei Formen in ς aufgelöst, und der Aufruf von lower () für beide Zeichenfolgen funktioniert ordnungsgemäß:

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

Wenn Sie sich also für Edge-Cases wie die drei griechischen Sigmas interessieren, verwenden Sie Python 3.

(Als Referenz werden Python 2.7.3 und Python 3.3.0b1 in den Ausdrucken des Interpreters oben gezeigt.)

57
Nathan Craike

Abschnitt 3.13 des Unicode-Standards definiert Algorithmen für den falllosen Abgleich.

X.casefold() == Y.casefold() in Python 3 implementiert den "standardmäßigen caseless matching" (D144).

Casefolding bewahrt die Normalisierung von Strings nicht in allen Fällen und daher muss die Normalisierung durchgeführt werden ('å' vs. 'å'). D145 führt "canonical caseless matching" ein:

import unicodedata

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

def canonical_caseless(text):
    return NFD(NFD(text).casefold())

NFD() wird zweimal für sehr seltene Edge-Fälle mit U + 0345-Zeichen aufgerufen.

Beispiel:

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

Es gibt auch Kompatibilitäts-Caseless-Matching (D146) für Fälle wie '㎒' (U + 3392) und "Identifier-Caseless-Matching" zur Vereinfachung und Optimierung Caseless-Matching von Identifiern .

30
jfs

Ich sah diese Lösung hier mit Regex .

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

Es funktioniert gut mit Akzenten

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

Bei Unicode-Zeichen wird jedoch nicht zwischen Groß- und Kleinschreibung unterschieden. Vielen Dank, @ Rhymoid, dass Sie darauf hingewiesen haben, dass meines Erachtens das genaue Symbol erforderlich ist, damit der Fall wahr ist. Die Ausgabe ist wie folgt:

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)
....:
7
Shiwangi

Die übliche Vorgehensweise besteht darin, die Zeichenfolgen in Groß- oder Kleinbuchstaben zu schreiben, um sie zu suchen und zu vergleichen. Zum Beispiel:

>>> "hello".upper() == "HELLO".upper()
True
>>> 
4
Andru Luvisi

Wie wäre es zuerst in Kleinbuchstaben zu konvertieren? Sie können string.lower() verwenden.

4

Dies ist eine weitere Regex, die ich in der letzten Woche lieben/hassen gelernt habe, also normalerweise als (in diesem Fall ja) etwas importieren, das widerspiegelt, wie ich mich fühle! mache eine normale Funktion .... frage nach Eingaben und benutze dann .... something = re.compile (r'foo * | spam * ', yes.I) ...... re.I (yes.I) unten) ist dasselbe wie IGNORECASE, aber Sie können nicht so viele Fehler machen, wenn Sie es schreiben!

Sie suchen dann Ihre Nachricht mit regulären Ausdrücken, aber ehrlich gesagt, sollte das ein paar Seiten für sich sein, aber der Punkt ist, dass Foo oder Spam zusammen geleitet werden und Groß- und Kleinschreibung ignoriert wird. Wenn dann eines von beiden gefunden wird, würde lost_n_found eines davon anzeigen. Wenn keiner von beiden ist, ist lost_n_found gleich None. Ist dies nicht der Fall, wird die Benutzereingabe mit "return lost_n_found.lower ()" in Kleinbuchstaben zurückgegeben.

Auf diese Weise können Sie viel einfacher zwischen Groß- und Kleinschreibung unterscheiden. Schließlich steht (NCS) für "niemand kümmert sich ernsthaft ...!" oder nicht case sensitive .... welcher auch immer

wenn jemand irgendwelche Fragen hat, melde dich bei mir.

    import re as yes

    def bar_or_spam():

        message = raw_input("\nEnter FoO for BaR or SpaM for EgGs (NCS): ") 

        message_in_coconut = yes.compile(r'foo*|spam*',  yes.I)

        lost_n_found = message_in_coconut.search(message).group()

        if lost_n_found != None:
            return lost_n_found.lower()
        else:
            print ("Make tea not love")
            return

    whatz_for_breakfast = bar_or_spam()

    if whatz_for_breakfast == foo:
        print ("BaR")

    Elif whatz_for_breakfast == spam:
        print ("EgGs")
0
Ali Paul