Unterschied zwischen InvariantCulture und Ordinal String Vergleich

548

Was ist der Unterschied zwischen InvariantCulture und Ordinalvergleich, wenn zwei Zeichenfolgen in c # auf Gleichheit verglichen werden?

Kapil
quelle
Vielleicht siao2.com/2004/12/29/344136.aspx ? (gegoogelt)
Cheese Daneish
2
Für diejenigen String1.Equals(String2, StringComparison.Ordinal), die es verwenden , ist es besser, es zu verwenden String1 == String2, da String1.Equals(String2)es sich um einen ordinalen Vergleich handelt, bei dem die Groß- und Kleinschreibung beachtet wird.
Ghasan
3
@Ghasan Ich bin mir nicht sicher, ob das =="besser" macht, aber es ist a) kürzer, b) weniger explizit darüber, was genau es tut und c) String1kann null sein, ohne dass der Vergleich a auslöst NullReferenceException.
Eugene Beresovsky
3
@Ghasan, die offiziellen Best Practices für MSDN zur Verwendung von Zeichenfolgen auf der .NET Framework- Seite ( msdn.microsoft.com/en-us/library/… ), empfiehlt die Verwendung von Überladungen, die den StringComparisonTyp explizit angeben . Im Fall eines Zeichenfolgenvergleichs bedeutet dies String.Equals.
Ohad Schneider
3
@EugeneBeresovsky Um dies zu vermeiden NullReferenceException, können Sie einfach die statische Methode verwenden : String.Equals(string1, string2, StringComparison.Ordinal).
Ohad Schneider

Antworten:

302

InvariantCulture

Verwendet einen "Standard" -Satz von Zeichenreihenfolgen (a, b, c, ... usw.). Dies steht im Gegensatz zu einigen bestimmten Gebietsschemas, in denen Zeichen in unterschiedlicher Reihenfolge sortiert werden können ("a-mit-akut" kann je nach Gebietsschema vor oder nach "a" stehen usw.).

Ordinal

Betrachtet man dagegen nur die Werte der Rohbytes, die das Zeichen darstellen.


Unter http://msdn.microsoft.com/en-us/library/e6883c06.aspx finden Sie ein großartiges Beispiel , das die Ergebnisse der verschiedenen StringComparison-Werte zeigt. Am Ende zeigt es (Auszug):

StringComparison.InvariantCulture:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is less than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

StringComparison.Ordinal:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is greater than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

Sie können sehen, wo InvariantCulture ergibt (U + 0069, U + 0049, U + 00131), Ordnungserträge (U + 0049, U + 0069, U + 00131).

JaredReisinger
quelle
25
Der ordinale Vergleich betrachtet die Codepunkte , nicht die Bytes.
Joey
144
Ich denke, es ist eine nützliche Information, aber ich beantworte die Frage nicht wirklich. Gibt es bei der Bestimmung der Gleichheit zweier Zeichenfolgen einen Grund, InvarintCulture anstelle von Ordinal zu verwenden? Es scheint, dass InvariantCulture verwendet wird, um Zeichenfolgen zu sortieren , und Ordinal sollte für die Gleichheitsprüfung verwendet werden (es ist uns egal, dass Akzent-a vor oder nach a steht, es ist einfach anders). Allerdings bin ich mir in diesem Punkt ein wenig unsicher.
MPavlak
18
Siehe msdn.microsoft.com/en-us/library/ms230117%28v=vs.90%29.aspx und beachten Sie, dass die Normalisierung von Zeichenfolgen und der Ordnungsvergleich empfohlen werden.
MPavlak
23
Ordinal ist viel schneller
Darren
9
Es wurden gute Leistungstestergebnisse veröffentlicht. C # -Stringvergleichstests geben Aufschluss über die Leistung der verschiedenen Stringvergleichsmethoden und deren Zeit.
Kumar C
262

Es ist zum Beispiel wichtig - es gibt eine Sache, die als Charaktererweiterung bezeichnet wird

var s1 = "Strasse";
var s2 = "Straße";

s1.Equals(s2, StringComparison.Ordinal);           //false
s1.Equals(s2, StringComparison.InvariantCulture);  //true

Mit InvariantCulturedem ß wird das Zeichen auf ss erweitert.

Ventsyslav Raikov
quelle
1
Unterscheidet sich dieses Ding auch in irgendeiner Weise zwischen Ordinalund InvariantCulture? Darum geht es in der ursprünglichen Frage.
Matthijs Wessels
3
Für diejenigen, die es nicht wissen ß, sollte beachtet werden, dass ßzumindest auf Deutsch ein Doppel s entspricht. Quelle: en.wikipedia.org/wiki/%C3%9F
Peter
20
Das ist nicht ganz richtig @Peter, Sie können nicht ßund ssaustauschbar in Deutsch (ich bin ein Muttersprachler). Es gibt Fälle, in denen beide legal sind (aber oft ist eines veraltet / nicht empfohlen), und es gibt Fälle, in denen nur ein Formular zulässig ist.
Enzi
5
Dieses einfache Beispiel zeigt deutlich den Unterschied zwischen den beiden Vergleichen. Ich glaube, ich bekomme das jetzt.
BrianLegg
4
Musste es versuchen: ideone.com/j8DvDo so cool! Eine kleine Lektion auch in Deutsch.
Ich frage mich,
111

Verweisen auf bewährte Methoden für die Verwendung von Zeichenfolgen in .NET Framework :

  • Verwenden Sie StringComparison.Ordinaloder StringComparison.OrdinalIgnoreCasefür Vergleiche als sicheren Standard für den kulturunabhängigen String-Abgleich.
  • Verwenden Sie Vergleiche mit StringComparison.Ordinaloder StringComparison.OrdinalIgnoreCasefür eine bessere Leistung.
  • Verwenden Sie nicht-sprachliche StringComparison.Ordinaloder StringComparison.OrdinalIgnoreCaseWerte anstelle von Zeichenfolgenoperationen, je nachdem, CultureInfo.InvariantCulturewann der Vergleich sprachlich irrelevant ist (z. B. symbolisch).

Und schlussendlich:

  • Verwenden Sie StringComparison.InvariantCulturein den meisten Fällen keine Zeichenfolgenoperationen basierend auf . Eine der wenigen Ausnahmen ist, wenn Sie sprachlich bedeutsame, aber kulturell agnostische Daten beibehalten.
Dariusz
quelle
56

Ein weiterer praktischer Unterschied (auf Englisch, wo Akzente ungewöhnlich sind) besteht darin, dass bei einem InvariantCulture-Vergleich die gesamten Zeichenfolgen zuerst nach Groß- und Kleinschreibung verglichen werden und dann, falls erforderlich (und angefordert), nach Groß- und Kleinschreibung unterschieden wird, nachdem zuerst nur die einzelnen Buchstaben verglichen wurden. (Sie können natürlich auch einen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung durchführen, bei dem nicht nach Groß- und Kleinschreibung unterschieden wird.) Korrigiert:Akzentuierte Buchstaben werden als eine andere Variante derselben Buchstaben betrachtet, und die Zeichenfolge wird verglichen, wobei zuerst Akzente ignoriert und dann berücksichtigt werden, wenn alle allgemeinen Buchstaben übereinstimmen (ähnlich wie bei unterschiedlichen Groß- und Kleinschreibung, außer dass sie bei einem Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung nicht letztendlich ignoriert werden). Diese Gruppe akzentuiert Versionen des ansonsten gleichen Wortes nahe beieinander, anstatt beim ersten Akzentunterschied vollständig getrennt zu sein. Dies ist die Sortierreihenfolge, die Sie normalerweise in einem Wörterbuch finden. Großgeschriebene Wörter werden direkt neben ihren Kleinbuchstaben angezeigt, und Buchstaben mit Akzent befinden sich in der Nähe des entsprechenden Buchstabens ohne Akzent.

Ein Ordnungsvergleich vergleicht streng die numerischen Zeichenwerte und endet bei der ersten Differenz. Dies sortiert großgeschriebene Buchstaben vollständig getrennt von den Kleinbuchstaben (und Akzentbuchstaben vermutlich getrennt von diesen), so dass großgeschriebene Wörter nicht annähernd ihre Kleinbuchstabenäquivalente sortieren würden.

InvariantCulture betrachtet Großbuchstaben auch als größer als Kleinbuchstaben, während Ordinal Großbuchstaben als kleiner als Kleinbuchstaben betrachtet (ein Überbleibsel von ASCII aus den alten Tagen, bevor Computer Kleinbuchstaben hatten, wurden die Großbuchstaben zuerst zugewiesen und hatten daher niedrigere Werte als die Kleinbuchstaben später hinzugefügt).

Zum Beispiel durch Ordinal: "0" < "9" < "A" < "Ab" < "Z" < "a" < "aB" < "ab" < "z" < "Á" < "Áb" < "á" < "áb"

Und von InvariantCulture: "0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"

Rob Parker
quelle
Ich habe mir das noch einmal angesehen und eine Inkonsistenz zwischen dem InvariantCulture-Beispiel und meiner Erklärung zum Umgang mit Zeichen mit Akzent festgestellt. Das Beispiel scheint korrekt zu sein, daher habe ich die Erklärung so korrigiert, dass sie konsistent ist. Der InvariantCulture-Vergleich hört nicht beim ersten unterschiedlichen Akzent auf und scheint nur dann einen Akzentunterschied für denselben Buchstaben zu berücksichtigen, wenn der Rest der Zeichenfolgen neben Akzenten und Groß- / Kleinschreibung übereinstimmt. Ein Akzentunterschied wird dann vor einem früheren Fallunterschied betrachtet, also "Aaba" <"aába".
Rob Parker
31

Obwohl es sich um eine Frage der Gleichheit handelt , wird hier zur schnellen visuellen Bezugnahme die Reihenfolge einiger Zeichenfolgen anhand einiger Kulturen sortiert , um einige der Besonderheiten zu veranschaulichen.

Ordinal          0 9 A Ab a aB aa ab ss Ä Äb ß ä äb      
IgnoreCase       0 9 a A aa ab Ab aB ss ä Ä äb Äb ß      
--------------------------------------------------------------------
InvariantCulture 0 9 a A  ä Ä aa ab aB Ab äb Äb ss ß     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ß ss     
--------------------------------------------------------------------
da-DK            0 9 a A  ab aB Ab ss ß ä Ä äb Äb aa     
IgnoreCase       0 9 A a  Ab aB ab ß ss Ä ä Äb äb aa     
--------------------------------------------------------------------
de-DE            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
en-US            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
ja-JP            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     

Beobachtungen:

  • de-DE, ja-JPUnd en-USsortieren die gleiche Art und Weise
  • Invariantnur sortiert ssund ßanders als die oben genannten drei Kulturen
  • da-DK sortiert ganz anders
  • Die IgnoreCaseFlagge ist für alle untersuchten Kulturen von Bedeutung

Der zum Generieren der obigen Tabelle verwendete Code:

var l = new List<string>
    { "0", "9", "A", "Ab", "a", "aB", "aa", "ab", "ss", "ß",
      "Ä", "Äb", "ä", "äb", "あ", "ぁ", "ア", "ァ", "A", "亜" };

foreach (var comparer in new[]
{
    StringComparer.Ordinal,
    StringComparer.OrdinalIgnoreCase,
    StringComparer.InvariantCulture,
    StringComparer.InvariantCultureIgnoreCase,
    StringComparer.Create(new CultureInfo("da-DK"), false),
    StringComparer.Create(new CultureInfo("da-DK"), true),
    StringComparer.Create(new CultureInfo("de-DE"), false),
    StringComparer.Create(new CultureInfo("de-DE"), true),
    StringComparer.Create(new CultureInfo("en-US"), false),
    StringComparer.Create(new CultureInfo("en-US"), true),
    StringComparer.Create(new CultureInfo("ja-JP"), false),
    StringComparer.Create(new CultureInfo("ja-JP"), true),
})
{
    l.Sort(comparer);
    Console.WriteLine(string.Join(" ", l));
}
Eugene Beresovsky
quelle
1
Hmmm - OK, es ist schön, dass Sie diese Nachforschungen angestellt und Ihre Ergebnisse veröffentlicht haben, obwohl ich nicht genau weiß, worum es Ihnen geht. Wie auch immer, Dänisch ist vielleicht keine der "wichtigsten Kulturen" (obwohl 5 Millionen Dänen ihre Kultur eigentlich eher mögen), aber wenn Sie "aa" als zusätzlichen Teststring und "da-DK" als Als zusätzliche Testkultur sehen Sie einige interessante Ergebnisse.
RenniePet
1
@RenniePet Danke dafür. Ich habe Dänisch hinzugefügt, da es ganz anders sortiert als die drei anderen verwendeten Kulturen. (Da Emoticons, die auf Ironie hinweisen, im englischsprachigen Lese-Web nicht so gut verstanden zu sein scheinen, wie ich angenommen hätte, habe ich den Kommentar "Wichtigste Kulturen" entfernt. Schließlich enthält die BCL keine, CultureComparerdie wir verwenden könnten Für diese Tabelle Danisherwies sich die Kultur (Info) als sehr wichtig.)
Eugene Beresovsky
1
Vielen Dank. Mir war klar, dass Ihr Kommentar zu den "wichtigsten Kulturen" mit einem Körnchen Salz aufgenommen werden sollte - ich bin nur zu alt geworden, um Emoticons zu verwenden. Ich denke, dass SMS so häufig geworden ist, dass die Verwendung von Emoticons so etwas wie das Erklären Ihrer Witze ist, nachdem Sie sie erzählt haben, unabhängig davon, ob jemand lacht oder nicht. Übrigens sind die anderen skandinavischen Kulturen (finnisch, norwegisch und schwedisch) die gleichen wie dänisch, mit Ausnahme des ganz besonderen Umgangs mit "aa" - was natürlich beweist, dass Dänisch die überlegene Kultur ist.
RenniePet
1
Für das, was es wert ist, sortiert Dänisch ä und aa unterschiedlich, da die Sonderbuchstaben æ (ae), ø (oe, ö) und å (aa, ä) am Ende des Alphabets in der schriftlichen Reihenfolge stehen.
Alrekr
5

Hier ist ein Beispiel, bei dem der Vergleich der Zeichenfolgengleichheit mit InvariantCultureIgnoreCase und OrdinalIgnoreCase nicht zu denselben Ergebnissen führt:

string str = "\xC4"; //A with umlaut, Ä
string A = str.Normalize(NormalizationForm.FormC);
//Length is 1, this will contain the single A with umlaut character (Ä)
string B = str.Normalize(NormalizationForm.FormD);
//Length is 2, this will contain an uppercase A followed by an umlaut combining character
bool equals1 = A.Equals(B, StringComparison.OrdinalIgnoreCase);
bool equals2 = A.Equals(B, StringComparison.InvariantCultureIgnoreCase);

Wenn Sie dies ausführen, ist equals1 falsch und equals2 ist true.

Dwedit
quelle
Nur um ein weiteres ähnliches Beispiel hinzuzufügen, aber mit String-Literalen, wenn a="\x00e9"(e akut) und b="\x0065\x0301"(e kombiniert mit einem akuten Akzent) StringComparer.Ordinal.Equals(a, b)false zurückgeben, während StringComparer.InvariantCulture.Equals(a, b)true zurückgegeben wird.
George Helyar
2

Sie müssen keine ausgefallenen Unicode-Zeichenbeispiele verwenden, um den Unterschied zu zeigen. Hier ist ein einfaches Beispiel, das ich heute herausgefunden habe und das überraschend ist und nur aus ASCII-Zeichen besteht.

Gemäß der ASCII-Tabelle ist 0(0x48) im _normalen Vergleich kleiner als (0x95). InvariantCulture würde das Gegenteil sagen (PowerShell-Code unten):

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1
KFL
quelle
-7

Versuchen Sie immer, InvariantCulture in den Zeichenfolgenmethoden zu verwenden, die dies als Überladung akzeptieren. Mit InvariantCulture sind Sie auf der sicheren Seite. Viele .NET-Programmierer verwenden diese Funktionalität möglicherweise nicht. Wenn Ihre Software jedoch von verschiedenen Kulturen verwendet wird, ist InvariantCulture eine äußerst praktische Funktion.

George
quelle
3
Wenn Ihre Software nicht von verschiedenen Kulturen verwendet wird, ist sie jedoch viel langsamer als Ordinal.
Kyle
4
Ich habe über eine Abstimmung nachgedacht, weil Sie Ihre zufällige Reaktion sicherlich nicht durchdacht haben. Obwohl darin ein Körnchen Wahrheit ist. WENN Ihre Anwendung auf mehrere Kulturen verteilt ist ... Das rechtfertigt sicherlich nicht Ihre einleitenden Worte "Versuchen Sie immer, InvariantCulture zu verwenden", oder? Ich bin überrascht, dass Sie über die Jahre nicht zurückgekommen sind, um diese Verrücktheit zu bearbeiten, nachdem Sie eine Abwertung und vielleicht mehr Erfahrung erhalten haben.
Suamere