15 Stimmen

Warum scheint string.Compare akzentuierte Zeichen uneinheitlich zu behandeln?

Wenn ich die folgende Anweisung ausführe:

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

Das Ergebnis ist "-1", was bedeutet, dass "mun" einen niedrigeren numerischen Wert hat als "mün".

Wenn ich jedoch diese Anweisung ausführe:

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

Ich erhalte eine "1", was bedeutet, dass "Muntelier, Schewiz" als letztes drankommen sollte.

Ist dies ein Fehler in dem Vergleich? Oder, was wahrscheinlicher ist, gibt es eine Regel, die ich berücksichtigen sollte, wenn ich Zeichenketten sortiere, die akzentuierte


Der Grund, warum dies ein Problem ist, ist, dass ich eine Liste sortiere und dann einen manuellen Binärfilter durchführe, der jede Zeichenfolge abrufen soll, die mit "xxx" beginnt.

Bisher habe ich die Linq-Methode "Where" verwendet, aber jetzt muss ich diese benutzerdefinierte Funktion verwenden, die von einer anderen Person geschrieben wurde, weil er sagt, dass sie besser funktioniert.

Aber die benutzerdefinierte Funktion scheint die 'Unicode'-Regeln von .NET nicht zu berücksichtigen. Wenn ich also sage, dass nach "mün" gefiltert werden soll, werden keine Einträge gefunden, obwohl es in der Liste Einträge gibt, die mit "mun" beginnen.

Dies scheint auf die inkonsistente Reihenfolge der akzentuierten Zeichen zurückzuführen zu sein, je nachdem, welche Zeichen auf das akzentuierte Zeichen folgen.


OK, ich glaube, ich habe das Problem gelöst.

Vor dem Filter führe ich eine Sortierung nach der ersten n Buchstaben der einzelnen Zeichenfolgen, wobei n ist die Länge des Suchstrings.

23voto

Adrian Punkte 1168

Es gibt einen Algorithmus, der bei einem Unentschieden entscheidet, siehe http://unicode.org/reports/tr10/

Zur Bewältigung der Komplexität der sprachsensitiven Sortierens zu begegnen, wird ein mehrstufiger Vergleichsalgorithmus verwendet. Beim Vergleich zweier Wörter, zum Beispiel zum Beispiel ist das wichtigste Merkmal das Basiszeichen: z. B. der Unterschied zwischen einem A und einem B. Akzentunterschiede werden normalerweise ignoriert, wenn es Unterschiede in den Grundbuchstaben gibt. Unterschiede in der Großschreibung (Großbuchstaben versus Kleinbuchstaben), werden in der Regel ignoriert, wenn es irgendwelche Unterschiede in der Basis oder den Akzenten gibt. Die Interpunktion ist variabel. In manchen Situationen wird ein Interpunktionszeichen wie ein Basiszeichen behandelt. In anderen Situationen sollte es ignoriert werden wenn es irgendwelche Unterschiede in der Basis, im Akzent oder in der Großschreibung Unterschiede gibt. Es kann auch eine endgültige, ausschlaggebende Stufe geben, wobei, wenn überhaupt keine anderen Unterschiede in der Zeichenkette gibt, wird die (normalisierte) Code Punkt-Reihenfolge verwendet wird.

So sind "Munt..." und "Münc..." alphabetisch unterschiedlich und werden nach dem "t" und "c" sortiert.

Da "mun" und "mün" alphabetisch gleich sind (das "u" entspricht dem "ü" in den verlorenen Sprachen), werden die Zeichencodes verglichen.

6voto

Jon Skeet Punkte 1325502

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

Hier ist ein Beispielcode zur Veranschaulichung:

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);
    }
}

(Ich habe auch versucht, nach dem "n" ein Leerzeichen einzufügen, um zu sehen, ob es sich um Wortgrenzen handelt - das ist nicht der Fall).

Ergebnisse:

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

Ich vermute, dass dies aufgrund verschiedener komplizierter Unicode-Regeln korrekt ist - aber ich weiß nicht genug darüber.

Ob Sie das berücksichtigen müssen... Ich würde es nicht erwarten. Was tun Sie, das dadurch ausgelöst wird?

4voto

Dirk Vollmar Punkte 166522

So wie ich das verstehe, ist es noch einigermaßen konsistent. Beim Vergleich mit CultureInfo.InvariantCulture das Umlautzeichen ü wird wie ein nicht akzentuiertes Zeichen behandelt u .

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

Ich konnte keine eindeutige Dokumentation in MSDN finden, die diese Regeln erklärt, 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);

ergibt das gewünschte Ergebnis.

Auf jeden Fall sollten Sie sich bei der Sortierung auf eine bestimmte Kultur stützen, z. B. auf die Kultur des aktuellen Benutzers (wenn möglich).

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