Groß- und Kleinschreibung

84

Ist es bei Vergleichen ohne Berücksichtigung der Groß- und Kleinschreibung effizienter, die Zeichenfolge in Groß- oder Kleinschreibung umzuwandeln? Ist es überhaupt wichtig?

In diesem SO-Beitrag wird vorgeschlagen, dass C # mit ToUpper effizienter ist, weil "Microsoft es auf diese Weise optimiert hat". Ich habe aber auch dieses Argument gelesen , dass das Konvertieren von ToLower vs. ToUpper davon abhängt, wovon Ihre Zeichenfolgen mehr enthalten, und dass Zeichenfolgen normalerweise mehr Kleinbuchstaben enthalten, was ToLower effizienter macht.

Insbesondere würde ich gerne wissen:

  • Gibt es eine Möglichkeit, ToUpper oder ToLower so zu optimieren, dass einer schneller als der andere ist?
  • Ist es schneller, einen Vergleich zwischen Groß- und Kleinschreibung ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen, und warum?
  • Gibt es Programmierumgebungen (z. B. C, C #, Python usw.), in denen ein Fall eindeutig besser ist als der andere, und warum?
Parappa
quelle

Antworten:

90

Die Umrechnung in Groß- oder Kleinbuchstaben, um Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen, ist aufgrund "interessanter" Merkmale einiger Kulturen, insbesondere der Türkei, falsch. Verwenden Sie stattdessen einen StringComparer mit den entsprechenden Optionen.

MSDN hat einige großartige Richtlinien für die Handhabung von Zeichenfolgen. Möglicherweise möchten Sie auch überprüfen, ob Ihr Code den Türkei-Test besteht .

BEARBEITEN: Beachten Sie Neils Kommentar zu ordinalen Vergleichen ohne Berücksichtigung der Groß- und Kleinschreibung. Dieses ganze Reich ist ziemlich trüb :(

Jon Skeet
quelle
15
Ja, StringComparer ist großartig, aber die Frage wurde nicht beantwortet ... In Situationen, in denen Sie StringComparer nicht verwenden können, z. B. eine swtich-Anweisung für einen String. soll ich ToUpper oder ToLower im Switch?
Joshperry
7
Verwenden Sie einen StringComparer und "if" / "else", anstatt entweder ToUpper oder ToLower zu verwenden.
Jon Skeet
5
John, ich weiß, dass die Konvertierung in Kleinbuchstaben falsch ist, aber ich hatte nicht gehört, dass die Konvertierung in Großbuchstaben falsch ist. Können Sie ein Beispiel oder eine Referenz anbieten? In dem von Ihnen verlinkten MSDN-Artikel heißt es: "Vergleiche, die mit OrdinalIgnoreCase durchgeführt wurden, bestehen verhaltensmäßig aus zwei Aufrufen: Aufrufen von ToUpperInvariant für beide Zeichenfolgenargumente und Durchführen eines Ordnungsvergleichs." Im Abschnitt "Ordinale Zeichenfolgenoperationen" wird dies im Code wiederholt.
Neil
2
@Neil: Interessant, ich hatte das bisschen nicht gesehen. Für einen ordinalen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung denke ich, dass dies fair genug ist. Es muss doch etwas auswählen . Für kulturell sensible Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung denke ich, dass es immer noch Raum für merkwürdiges Verhalten gibt. Ich werde auf Ihren Kommentar in der Antwort hinweisen ...
Jon Skeet
4
@Triynko: Ich denke, es ist wichtig, sich in erster Linie auf die Richtigkeit zu konzentrieren , mit dem Punkt, dass es normalerweise nicht besser (und manchmal schlechter) ist, schnell die falsche Antwort zu erhalten, als langsam die falsche Antwort zu bekommen.
Jon Skeet
25

Von Microsoft auf MSDN:

Best Practices für die Verwendung von Zeichenfolgen in .NET Framework

Empfehlungen für die Verwendung von Zeichenfolgen

Warum? Von Microsoft :

Normalisieren Sie Zeichenfolgen in Großbuchstaben

Es gibt eine kleine Gruppe von Zeichen, die bei Konvertierung in Kleinbuchstaben keine Rundreise machen können.

Was ist ein Beispiel für einen solchen Charakter, der keine Rundreise machen kann?

  • Anfang : Griechisches Rho-Symbol (U + 03f1) ϱ
  • Großbuchstaben: Hauptstadt Griechisch Rho (U + 03a1) Ρ
  • Kleinbuchstaben: Kleiner griechischer Rho (U + 03c1) ρ

ϱ, Ρ , ρ

.NET Geige

Original: ϱ
ToUpper: Ρ
ToLower: ρ

Wenn Sie Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung durchführen möchten, konvertieren Sie die Zeichenfolgen daher in Großbuchstaben und nicht in Kleinbuchstaben.

Wenn Sie also einen auswählen müssen, wählen Sie Großbuchstaben .

Ian Boyd
quelle
und was ist der grund
Bjan
@bjan Der Grund ist, weil es schlecht ist, nicht zu.
Ian Boyd
1
Welche Gruppe von Charakteren? Was bedeutet eine Rundreise überhaupt?
Johv
1
@johv Über den Link: "Eine Rundreise zu machen bedeutet, die Zeichen von einem Gebietsschema in ein anderes Gebietsschema zu konvertieren, das die Zeichendaten unterschiedlich darstellt, und dann die ursprünglichen Zeichen aus den konvertierten Zeichen genau abzurufen." Welche Gruppe von Charakteren? Ich weiß es nicht, aber ich werde die Kleinbuchstaben iauf Türkisch erraten , wann sie werden İ, und nicht die I, an die Sie gewöhnt sind. Wir sind es auch gewohnt, in Großbuchstaben zu Ischreiben i, aber in der Türkei wird es ı.
Ian Boyd
3
Zurück zur Antwort auf die ursprüngliche Frage: Es gibt Sprachen, die mehr als eine Kleinbuchstabenvariante für eine Großbuchstabenvariante kennen. Sofern Sie nicht wissen, wann welche Darstellung verwendet werden soll (ein weiteres Beispiel auf Griechisch: kleiner Sigma-Buchstabe, verwenden Sie σ am Wortanfang oder in der Mitte, ς am Wortende (siehe en.wikipedia.org/wiki/Sigma )). Sie können nicht sicher zurück in die Kleinbuchstabenvariante konvertieren.
Aconcagua
19

Laut MSDN ist es effizienter, die Zeichenfolgen zu übergeben und den Vergleich anzuweisen, Groß- und Kleinschreibung zu ignorieren:

String.Compare (strA, strB, StringComparison.OrdinalIgnoreCase) entspricht ( aber schneller als Aufruf )

String.Compare (ToUpperInvariant (strA), ToUpperInvariant (strB), StringComparison.Ordinal).

Diese Vergleiche sind immer noch sehr schnell.

Wenn Sie eine Zeichenfolge immer wieder vergleichen, gilt dies möglicherweise nicht.

Rob Walker
quelle
12

Basierend auf Zeichenfolgen, die tendenziell mehr Einträge in Kleinbuchstaben enthalten, sollte ToLower theoretisch schneller sein (viele Vergleiche, aber nur wenige Zuweisungen).

In C oder wenn einzeln zugängliche Elemente jeder Zeichenfolge verwendet werden (z. B. C-Zeichenfolgen oder der Zeichenfolgentyp der STL in C ++), handelt es sich tatsächlich um einen Byte-Vergleich. Der Vergleich unterscheidet sich UPPERalso nicht vonlower .

Wenn Sie hinterhältig waren und Ihre Saiten in geladen haben long stattdessen Arrays würden, würden Sie einen sehr schnellen Vergleich für die gesamte Zeichenfolge erhalten, da 4 Bytes gleichzeitig verglichen werden könnten. Aufgrund der Ladezeit lohnt es sich jedoch möglicherweise nicht.

Warum müssen Sie wissen, was schneller ist? Wenn Sie nicht eine ganze Reihe von Vergleichen durchführen, ist eine, die ein paar Zyklen schneller ausgeführt wird, für die Geschwindigkeit der Gesamtausführung irrelevant und klingt nach vorzeitiger Optimierung :)

Labyrinth
quelle
11
Um die Frage zu beantworten, warum ich wissen muss, was schneller ist: Ich muss es nicht wissen, ich möchte es nur wissen. :) Es geht einfach darum, jemanden zu sehen, der eine Behauptung aufstellt (z. B. "Vergleichen von Großbuchstaben ist schneller!") Und zu wissen, ob dies wirklich der Fall ist und / oder warum er diese Behauptung aufstellt.
Parappa
1
das macht Sinn - ich bin auch ewig neugierig auf solche Sachen :)
warren
Wenn Sie mit C-Zeichenfolgen sund tin Arrays von Longs konvertieren möchten, sodass die Zeichenfolgen gleich sind, wenn die Arrays gleich sind, müssen Sie s und t nach unten gehen, bis Sie das abschließende '\0'Zeichen gefunden haben (oder Sie können den Müll nach dem Ende der Zeichenfolgen vergleichen). Dies kann ein unzulässiger Speicherzugriff sein, der undefiniertes Verhalten hervorruft. Aber warum nicht einfach die Vergleiche anstellen, während Sie nacheinander über die Charaktere gehen? Mit C ++ - Zeichenfolgen können Sie wahrscheinlich die Länge .c_str()abrufen long *und ein Präfix der Länge in a umwandeln und vergleichen .size() - .size()%(sizeof long). Sieht für mich ein bisschen faul aus.
Jonas Kölker
6

Microsoft hat optimiert ToUpperInvariant(), nicht ToUpper(). Der Unterschied ist, dass Invariante kulturfreundlicher ist. Wenn Sie Vergleiche zwischen Zeichenfolgen, die in der Kultur variieren können, ohne Berücksichtigung der Groß- und Kleinschreibung durchführen müssen, verwenden Sie Invariant. Andernfalls sollte die Leistung der invarianten Konvertierung keine Rolle spielen.

Ich kann nicht sagen, ob ToUpper () oder ToLower () schneller ist. Ich habe es nie versucht, da ich noch nie eine Situation hatte, in der Leistung so wichtig war.

Dan Herbert
quelle
Wenn Microsoft den Code für die Durchführung von Großbuchstabenvergleichen optimiert hat, liegt das daran, dass der ASCII-Code für Großbuchstaben nur aus zwei Ziffern 65 - 90 besteht, während der ASCII-Code aus Kleinbuchstaben 97 - 122 besteht, die drei Ziffern enthalten (weitere Verarbeitung erforderlich)?
Medo Medo
3
@Medo Ich erinnere mich nicht an die genauen Gründe für die Optimierung, aber 2 gegen 3 Ziffern sind mit ziemlicher Sicherheit nicht der Grund, da alle Buchstaben als Binärzahlen gespeichert sind, sodass Dezimalstellen aufgrund ihrer Art der Speicherung keine wirkliche Bedeutung haben.
Dan Herbert
4

Wenn Sie einen Zeichenfolgenvergleich in C # durchführen, ist die Verwendung von .Equals () erheblich schneller, anstatt beide Zeichenfolgen in Groß- oder Kleinschreibung zu konvertieren. Ein weiteres großes Plus bei der Verwendung von .Equals () ist, dass nicht mehr Speicher für die 2 neuen Groß- / Kleinbuchstaben zugewiesen wird.

Jon Tackabury
quelle
4
Und als Bonus, wenn Sie die richtigen Optionen auswählen, erhalten Sie tatsächlich die richtigen Ergebnisse :)
Jon Skeet
1

Es sollte wirklich nie wichtig sein. Bei ASCII-Zeichen spielt das definitiv keine Rolle - es sind nur ein paar Vergleiche und ein bisschen Flip für beide Richtungen. Unicode ist möglicherweise etwas komplizierter, da es einige Zeichen gibt, die die Groß- und Kleinschreibung auf seltsame Weise ändern, aber es sollte wirklich keinen Unterschied geben, es sei denn, Ihr Text ist voll mit diesen Sonderzeichen.

Adam Rosenfield
quelle
1

Wenn Sie es richtig machen, sollte es einen kleinen, unbedeutenden Geschwindigkeitsvorteil geben, wenn Sie in Kleinbuchstaben konvertieren. Dies ist jedoch, wie viele angedeutet haben, kulturabhängig und erbt nicht in der Funktion, sondern in den von Ihnen konvertierten Zeichenfolgen (viele Kleinbuchstaben) bedeutet nur wenige Zuweisungen zum Speicher) - die Konvertierung in Großbuchstaben ist schneller, wenn Sie eine Zeichenfolge mit vielen Großbuchstaben haben.

Klarer
quelle
0

Es hängt davon ab, ob. Wie oben angegeben, nur ASCII, es ist identisch. Lesen und verwenden Sie in .NET String.Compare für das i18n- Material (Sprachkulturen und Unicode). Wenn Sie etwas über die Wahrscheinlichkeit der Eingabe wissen, verwenden Sie den allgemeineren Fall.

Denken Sie daran, wenn Sie mehrere Zeichenfolgen vergleichen, ist die Länge ein ausgezeichneter erster Diskriminator.

Sanjaya R.
quelle
-2

Wenn Sie es mit reinem ASCII zu tun haben, spielt es keine Rolle. Es ist nur ein ODER x, 32 gegen ein UND x, 224. Unicode, ich habe keine Ahnung ...

Brian Knoblauch
quelle
4
Dies ist völlig falsch - OR'ing mit 32 funktioniert nur für AZ und die Zeichen 64-127; es vermasselt alle anderen Charaktere. AND'ing mit 32 ist noch falscher - das Ergebnis ist immer 0 (nul) oder 32 (Leerzeichen).
Adam Rosenfield