784 Stimmen

Wie führe ich einen String-Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung durch?

Wie kann ich Groß-/Kleinschreibung unempfindlich String-Vergleich in Python tun?

Ich möchte den Vergleich einer regulären Zeichenkette mit einer Repository-Zeichenkette auf eine sehr einfache und pythonische Weise kapseln. Ich möchte auch die Möglichkeit haben, Werte in einem Diktat von Zeichenfolgen mit regulären Python Zeichenfolgen gehasht nachschlagen.

804voto

Harley Holcombe Punkte 165146

Annahme von 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)")

Ab Python 3.3, casefold() ist eine bessere Alternative:

string1 = 'Hello'
string2 = 'hello'

if string1.casefold() == string2.casefold():
    print("The strings are the same (case insensitive)")
else:
    print("The strings are NOT the same (case insensitive)")

Wenn Sie eine umfassendere Lösung wünschen, die komplexere Unicode-Vergleiche handhabt, lesen Sie bitte die anderen Antworten.

89 Stimmen

Das klappt nicht immer. Es gibt zum Beispiel zwei griechische Sigmas, von denen eines nur am Ende verwendet wird. Die Zeichenfolge ("Sísyphos", oder besser "Síyphos") hat alle drei: Großbuchstaben am Anfang, Kleinbuchstaben am Ende und Kleinbuchstaben an der dritten Stelle, die keine Endbuchstaben sind. Wenn Ihre beiden Zeichenfolgen y dann scheitert Ihr Ansatz, weil es sich dabei unsinnigerweise um denselben Fall handeln soll.

66 Stimmen

@ Die letzten beiden Kommentatoren: Ich denke, man kann davon ausgehen, dass es sich bei beiden Zeichenfolgen um ASCII-Zeichenfolgen handelt. Wenn Sie nach einer Antwort auf etwas Spannenderes suchen, bin ich mir sicher, dass sie da draußen ist (oder Sie können sie fragen).

7 Stimmen

Der .lower()-Ansatz funktioniert in Python 3, zumindest für die beiden oben erwähnten griechischen Zeichenketten. Siehe meine Antwort für weitere Details.

719voto

Veedrac Punkte 54089

Der Vergleich von Zeichenketten ohne Berücksichtigung der Groß- und Kleinschreibung scheint trivial, ist es aber nicht. Ich werde Python 3 verwenden, da Python 2 hier unterentwickelt ist.

Zunächst einmal ist zu beachten, dass die Umwandlung von Groß- und Kleinschreibung in Unicode nicht trivial ist. Es gibt Text, für den text.lower() != text.upper().lower() , wie zum Beispiel "ß" :

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

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

Aber nehmen wir mal an, Sie wollten falllos vergleichen "BUSSE" y "Buße" . Wahrscheinlich wollen Sie auch vergleichen "BUSSE" y "BUE" gleich - das ist die neuere Großbuchstabenform. Der empfohlene Weg ist die Verwendung von casefold :

str. Fallfalte ()

Gibt eine gefaltete Kopie der Zeichenkette zurück. Gefaltete Zeichenketten können verwendet werden für falllosen Abgleich verwendet werden.

Die Groß-/Kleinschreibung ist ähnlich wie die Kleinschreibung, aber aggressiver, da sie alle Unterscheidungen zwischen Groß- und Kleinschreibung in einer Zeichenkette aufheben soll. [...]

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

Dann sollten Sie über Akzente nachdenken. Wenn Ihr Schrift-Renderer gut ist, denken Sie wahrscheinlich "ê" == "e" - aber das tut sie nicht:

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

Der Grund dafür ist, dass der Akzent bei letzterem ein kombinierendes Zeichen ist.

import unicodedata

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

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

Der einfachste Weg, damit umzugehen, ist unicodedata.normalize . Sie möchten wahrscheinlich NFKD Normalisierung aber sehen Sie sich ruhig die Dokumentation an. Dann tut man

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

Abschließend sei gesagt, dass dies in Funktionen ausgedrückt wird:

import unicodedata

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

def caseless_equal(left, right):
    return normalize_caseless(left) == normalize_caseless(right)

16 Stimmen

Eine bessere Lösung ist es, alle Zeichenketten bei der Aufnahme zu normalisieren, dann können Sie einfach x.casefold() == y.casefold() für case-insensitive Vergleiche (und, was noch wichtiger ist, x == y für Groß- und Kleinschreibung).

7 Stimmen

@abarnert Ja, das hängt vom Kontext ab - manchmal ist es besser, den Quelltext intakt zu lassen, aber eine Normalisierung im Vorfeld kann auch den späteren Code wesentlich vereinfachen.

5 Stimmen

@Veedrac: Du hast recht, es ist nicht immer angebracht; wenn du in der Lage sein musst, die ursprüngliche Quelle unverändert auszugeben (z.B. weil du mit Dateinamen unter Linux zu tun hast, wo NKFC und NKFD beide erlaubt sind und explizit unterschiedlich sein sollen), kannst du sie natürlich nicht bei der Eingabe umwandeln

65voto

Nathan Craike Punkte 4595

Bei Verwendung von Python 2 kann der Aufruf von .lower() für jede Zeichenkette oder jedes Unicode-Objekt...

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

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

Angenommen, wir haben eine Datei namens unicode.txt mit den beiden Zeichenketten y . 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 Kleinbuchstabenformen, und , und .lower() hilft nicht, sie fallunsensibel zu vergleichen.

Ab Python 3 werden jedoch alle drei Formen in , aufgelöst, und der Aufruf von lower() für beide Zeichenketten funktioniert korrekt:

>>> 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 Randfälle wie die drei Sigmas im Griechischen interessieren, sollten Sie Python 3 verwenden.

(Als Referenz sind Python 2.7.3 und Python 3.3.0b1 in den obigen Interpreter-Ausdrucken zu sehen).

20 Stimmen

Um den Vergleich noch robuster zu machen, können Sie ab Python 3.3 casefold verwenden (z. B. first.casefold() == second.casefold()). Für Python 2 können Sie PyICU verwenden (siehe auch: icu-project.org/apiref/icu4c/ )

59voto

jfs Punkte 370717

Abschnitt 3.13 der Unicode-Norm definiert Algorithmen für fallfreie Abgleich.

X.casefold() == Y.casefold() in Python 3 implementiert das "default caseless matching" (D144).

Beim Casefolding wird die Normalisierung von Zeichenketten nicht in allen Fällen beibehalten, weshalb die Normalisierung nachgeholt werden muss ( 'å' vs. 'a' ). D145 führt den "kanonischen fallfreien Abgleich" ein:

import unicodedata

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

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

NFD() wird in sehr seltenen Fällen, die das Zeichen U+0345 betreffen, zweimal aufgerufen.

Beispiel:

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

Es gibt auch Kompatibilität hülsenlos passend (D146) für Fälle wie '' (U+3392) und "identifier caseless matching" zur Vereinfachung und Optimierung fallfreier Abgleich von Identifikatoren .

6 Stimmen

Dies ist die beste Antwort für Python 3, da Python 3 Unicode-Zeichenfolgen verwendet und die Antwort beschreibt, wie der Unicode-Standard die Übereinstimmung von Zeichenfolgen ohne Groß-/Kleinschreibung definiert.

0 Stimmen

Leider ist seit Python 3.6 die casefold() Funktion implementiert nicht die Sonderbehandlung von Großbuchstaben I und gepunkteten Großbuchstaben I, wie sie in Eigenschaften von Faltkisten . Daher kann der Vergleich bei Wörtern aus türkischen Sprachen, die diese Buchstaben enthalten, fehlschlagen. Zum Beispiel, canonical_caseless('LMANI') == canonical_caseless('liman') muss zurückkehren True aber er liefert False . Derzeit besteht die einzige Möglichkeit, dies in Python zu bewerkstelligen, darin, einen Casefold-Wrapper zu schreiben oder eine externe Unicode-Bibliothek wie PyICU zu verwenden.

0 Stimmen

@SergiyKolesnikov .casefold() verhält sich so, wie es sein sollte, soweit ich das beurteilen kann. Aus dem Standard: "Die Standard-Gehäuseoperationen sind für die Verwendung im Abwesenheit der Anpassung an bestimmte Sprachen und Umgebungen" . Die Regeln für die Schreibweise des türkischen gepunkteten großen I und des punktlosen kleinen i sind in SpecialCasing.txt enthalten. "Für nicht-türkische Sprachen wird diese Zuordnung normalerweise nicht verwendet." Aus den Unicode FAQ: F: Warum gibt es keine extra kodierten Zeichen, um die lokal-unabhängige Schreibweise für Türkisch zu unterstützen?

10voto

mpriya Punkte 613

Sie können die Methode casefold() verwenden. Die Methode casefold() ignoriert Groß- und Kleinschreibung beim Vergleich.

firstString = "Hi EVERYONE"
secondString = "Hi everyone"

if firstString.casefold() == secondString.casefold():
    print('The strings are equal.')
else:
    print('The strings are not equal.')

Ausgabe:

The strings are equal.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X