2009-09-03 7 views
14

Wenn ich die folgende Anweisung ausführen:Warum scheint string.Compare Akzentzeichen nicht konsistent zu behandeln?

string.Compare("mun", "mün", true, CultureInfo.InvariantCulture) 

Das Ergebnis ist ‚-1‘, was darauf hinweist, dass ‚mun‘ einen niedrigeren numerischen Wert als ‚Mün‘ hat.

Allerdings, wenn ich diese Anweisung ausführen:

string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture) 

I '1' erhalten, was darauf hinweist, dass 'Muntelier, Schewiz' liest gehen soll.

Ist das ein Fehler im Vergleich? Oder, was wahrscheinlicher ist, ist es eine Regel sollte ich in Betracht nehmen, wenn Strings Sortierung mit Akzent enthält


Der Grund dafür ist ein Problem ist, ich bin eine Liste sortieren und dann eine manuelle Binärfilter zu tun, die gemeint ist um jeden String mit 'xxx' beginnen zu lassen.

Zuvor verwendete ich die Linq 'Where' Methode, aber jetzt muss ich diese benutzerdefinierte Funktion von einer anderen Person geschrieben verwenden, weil er sagt, dass es besser funktioniert.

Aber die benutzerdefinierte Funktion scheint nicht zu berücksichtigen, was auch immer Unicode-Regeln .NET hat. Wenn ich also sage, dass es nach 'mün' filtern soll, findet es keine Einträge, obwohl es in der Liste Einträge gibt, die mit 'mun' beginnen.

Dies scheint wegen der inkonsistenten Reihenfolge der Akzentzeichen, abhängig davon, welche Zeichen nach dem Akzentzeichen gehen.


OK, ich denke, ich habe das Problem behoben.

vor dem Filter, mache ich eine Art basierend auf den ersten n Buchstaben jeden Zeichenfolge, wo n die Länge des Suchbegriffs ist.

+0

Es ist Momente wie diese, die ich das .NET Framework wünschen war Open-Source, also konnte ich einfach im Debug-Modus durchgehen und genau herausfinden, was es macht. – Jonathan

+4

@jonathanconway: Das Durchlaufen des Quellcodes der Basisklassenbibliothek ist möglich, siehe http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net- framework-source-code.aspx –

+0

@ divo Danke für die Referenz. Habe nie realisiert, dass das möglich war! – Jonathan

Antwort

22

es ein Tie-breaking ist Algorithmus bei der Arbeit finden http://unicode.org/reports/tr10/

Um die Komplexität der sprachsensitiven Sortier zu adressieren, ein Multi-Level-Vergleichsalgorithmus ist eingesetzt. Im Vergleich von zwei Worten, für Beispiel, das wichtigste Merkmal ist die Basiszeichen: wie der Unterschied zwischen einer A- und einer B Accent Unterschiede sind in der Regel ignoriert, wenn es irgendwelche Unterschiede Buchstaben in der Basis sind. Fallunterschiede (Groß-/Kleinschreibung), werden normalerweise ignoriert, wenn Unterschiede in der Basis oder Akzente gibt. Interpunktion ist variabel. In einigen Situationen ist ein Interpunktionszeichen behandelt wie ein Basiszeichen. In anderen Situationen, sollte es ignoriert werden , wenn es eine Basis, Akzent oder Case Unterschiede gibt. Es kann auch eine endgültige, tie-breaking-Ebene geben, wobei, wenn keine anderen Unterschiede in der Zeichenfolge insgesamt sind, die (normalisierte) Code Punkt Reihenfolge verwendet wird.

Also, "Munt ..." und "Münc ..." sind alphabetisch unterschiedlich und sortieren nach dem "t" und "c".

Während „mun“ und „Mün“ sind alphabetisch gleich sind („u“ equivelent zu „ü“ in verlorenen Sprachen), so dass die Zeichencodes verglichen werden

6

Es sieht so aus, als ob das akzentuierte Zeichen nur in einer Art "tie-break" -Situation verwendet wird - mit anderen Worten, wenn die Strings ansonsten gleich sind.

Hier einige Beispiel-Code zu zeigen: (. Ich habe versucht, einen Raum nach dem „n“ als auch das Hinzufügen, um zu sehen, ob es auf Wortgrenzen getan wurde - ist es nicht)

using System; 
using System.Globalization; 

class Test 
{ 
    static void Main() 
    { 
     Compare("mun", "mün"); 
     Compare("muna", "münb"); 
     Compare("munb", "müna"); 
    } 

    static void Compare(string x, string y) 
    { 
     int result = string.Compare(x, y, true, 
            CultureInfo.InvariantCulture)); 

     Console.WriteLine("{0}; {1}; {2}", x, y, result); 
    } 
} 

Ergebnisse:

mun; mün; -1 
muna; münb; -1 
munb; müna; 1 

ich vermute, dies durch verschiedene komplizierte Unicode-Regeln korrekt ist - aber ich weiß über sie nicht genug.

Ob Sie dies berücksichtigen müssen ... würde ich nicht erwarten. Was machst du, was wird dadurch ausgelöst?

4

Wie ich verstehe, ist es immer noch etwas konsistent. Beim Vergleich mit CultureInfo.InvariantCulture wird das Umlautzeichen ü wie das nicht akzentuierte Zeichen u behandelt.

Da die Strings in Ihrem ersten Beispiel offensichtlich nicht gleich sind, ist das Ergebnis nicht 0, sondern -1 (was ein Standardwert zu sein scheint). Im zweiten Beispiel Muntelier geht zuletzt weil t folgt c im Alphabet.

Ich konnte keine klare Dokumentation in MSDN finden diese Regeln zu erklären, aber ich fand, dass

string.Compare("mun", "mün", CultureInfo.InvariantCulture, 
    CompareOptions.StringSort); 

und

string.Compare("Muntelier, Schweiz", "München, Deutschland", 
    CultureInfo.InvariantCulture, CompareOptions.StringSort); 

das gewünschte Ergebnis liefert.

Wie auch immer, ich denke, es wäre besser, wenn Sie Ihre Sortierung nach einer bestimmten Kultur wie der Kultur des aktuellen Benutzers ausrichten (wenn möglich).

+0

'CompareOptions.Ordinal' könnte auch eine Option sein. Mit dieser Option werden die Strings basierend auf den Unicode-Werten verglichen. Siehe http://msdn.microsoft.com/en-us/library/system.globalization.compareoptions.aspx. –