2009-09-03 12 views
14

Gdybym wykonać następujące oświadczenie:Dlaczego string.Compare wydaje się obsługiwać znaki akcentowane niekonsekwentnie?

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

Rezultatem jest „-1”, wskazując, że „mun” ma mniejszą wartość liczbową niż „Mun”.

Jednakże, jeśli mogę wykonać to stwierdzenie:

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

I get '1', wskazując, że 'Muntelier, Schewiz' powinien przejść ostatni.

Czy to błąd w porównaniu? Lub, co bardziej prawdopodobne, czy istnieje przepis powinien brać pod uwagę podczas sortowania ciągi zawierające akcentowane


Powodem jest to problem jest, mam do sortowania listy, a następnie robi ręcznego filtra binarny który oznaczał aby uzyskać każdy ciąg rozpoczynający się od "xxx".

Wcześniej używałem LINQ „gdzie” metodę, ale teraz muszę używać tej funkcji niestandardowych napisany przez inną osobę, ponieważ twierdzi, że działa lepiej.

ale funkcja zwyczaj nie wydaje się uwzględniać cokolwiek zasady „unicode” NET. Jeśli więc powiem, żeby filtrował według "mün", nie znajduje żadnych elementów, nawet jeśli na liście znajdują się elementy zaczynające się od "mun".

To wydaje się być ze względu na niespójne uporządkowania znaków diakrytycznych, w zależności od tego, które znaki iść po akcentowanym charakteru.


OK, chyba naprawiłem problem.

przed filtrem, zrobić coś w rodzaju na podstawie pierwszego n liter każdej struny, gdzie n jest długością łańcucha wyszukiwania.

+0

To chwile tak że życzę .NET Framework był open-source, więc mogłem po prostu przejść przez tryb debugowania i dowiedzieć się, co dokładnie robi. – Jonathan

+4

@jonathanconway: Możliwe jest przejście do kodu źródłowego biblioteki klasy podstawowej, patrz http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net- framework-source-code.aspx –

+0

@divo Dzięki za referencje. Nigdy nie zdawałem sobie sprawy, że to możliwe! – Jonathan

Odpowiedz

22

Jest algorytm tie-breaking w pracy, patrz http://unicode.org/reports/tr10/

Aby rozwiązać zawiłości języka wrażliwe sortowania, wielopoziomowy algorytm porównania jest rachunek. Porównując dwa słowa, na przykład, najważniejszą cechą jest postać podstawa: takie jak różnica umowę między A i B. Accent różnice są zazwyczaj ignorowane, czy są jakieś różnice w pismach bazowych. Różnice wielkości liter (wielkie litery i małe litery) są zwykle ignorowane, jeśli występują różnice w bazie lub akcentach. Interpunkcja jest zmienna. W niektórych sytuacjach znak interpunkcyjny jest traktowany jak znak bazowy. W innych sytuacjach należy zignorować , jeśli występują różnice w podstawach, akcentach lub przypadku: . Może również istnieć ostateczny poziom tie-breaking, przy czym jeśli nie ma żadnych innych różnic w łańcuchu, użyta zostanie kolejność punktów .

Tak więc, "Munt ..." i "Münc ..." są alfabetycznie różne i sortowane według "t" i "c".

Natomiast „Mun” i „Mun” są alfabetycznie takie same („u” equivelent do „U” w utraconych językach), więc kody znaków są porównywane

6

To wygląda jak znak akcentowany jest tylko używany w rodzaju sytuacji „tie-break” - innymi słowy, jeśli ciągi są równe inaczej.

Oto niektóre przykładowy kod, aby wykazać, że: (. Próbowałem dodając spację po „n”, a także, aby sprawdzić, czy to było robione na granicy słów - nie jest)

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

Wyniki:

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

I podejrzewam, że jest poprawna różnymi zasadami skomplikowane Unicode - ale nie wiem wystarczająco dużo o nich.

Co do tego, czy trzeba wziąć to pod uwagę ... Nie spodziewałbym się więc. Co robisz, to jest przez to rzucane?

4

Jak rozumiem to jest to nadal dość spójne. Porównując używając CultureInfo.InvariantCulture, znak umlaut jest traktowany jak niepustony znak u.

Ponieważ ciągi w twoim pierwszym przykładzie oczywiście nie są równe, wynik nie będzie wynosił 0, ale -1 (co wydaje się być wartością domyślną). W drugim przykładzie: Muntelier jest ostatnim, ponieważ t następuje po c w alfabecie.

nie mogłem znaleźć żadnych jasnych dokumentację w MSDN wyjaśniający te zasady, ale okazało się, że

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

i

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

daje pożądanego rezultatu.

W każdym razie myślę, że lepiej będzie oprzeć sortowanie na określonej kulturze, takiej jak kultura aktualnego użytkownika (jeśli to możliwe).

+0

'CompareOptions.Ordinal' może być również opcją. Dzięki tej opcji łańcuchy będą porównywane na podstawie wartości Unicode. Zobacz http://msdn.microsoft.com/en-us/library/system.globalization.compareoptions.aspx. –

Powiązane problemy