2009-09-03 13 views
14

Se eseguire l'istruzione seguente:Perché string.Compare sembra gestire i caratteri accentati in modo incoerente?

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

Il risultato è '-1', indicando che 'mun' ha un valore numerico inferiore 'Mün'.

Tuttavia, se eseguo questa dichiarazione:

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

ottengo '1', indicando che 'Muntelier, Schewiz' dovrebbe andare scorso.

Si tratta di un bug nel confronto? O, più probabilmente, c'è una regola dovrei prendere in considerazione durante l'ordinamento stringhe contenenti accentati


Il motivo di questo è un problema è, sto ordinamento di un elenco e poi fare un filtro binario manuale che è destinata per ottenere ogni stringa che inizia con 'xxx'.

In precedenza stavo usando il metodo Linq 'Dove', ma ora devo usare questa funzione personalizzata scritta da un'altra persona, perché dice che funziona meglio.

Ma la funzione personalizzata non sembra prendere in considerazione le regole "unicode" di .NET. Quindi se dico di filtrare per 'mün', non trova alcun elemento, anche se ci sono elementi nella lista che iniziano con 'mun'.

Questo sembra essere a causa dell'ordine incoerente di caratteri accentati, a seconda di quali caratteri vanno dopo il carattere accentato.


OK, penso di aver risolto il problema.

prima del filtro, faccio una specie in base ai primi n lettere di ogni stringa, dove n è la lunghezza della stringa di ricerca.

+0

E 'momenti come questo che vorrei che il .NET Framework era open-source, quindi ho potuto semplicemente passare in modalità debug e capire esattamente cosa sta facendo. – Jonathan

+4

@jonathanconway: è possibile passare al codice sorgente della libreria di classi base, vedere http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net- framework-source-code.aspx –

+0

@divo Grazie per il riferimento. Non ho mai realizzato che fosse possibile! – Jonathan

risposta

22

Esiste un algoritmo spareggio al lavoro, vedi http://unicode.org/reports/tr10/

Per affrontare le complessità della ordinamento sensibile alla lingua, un algoritmo di confronto multilivello è impiegato. Nel confronto tra due parole, per esempio, la caratteristica più importante è il carattere di base: come la differenza tra un A e B. differenze un accento sono tipicamente ignorato, se ci sono differenze nelle lettere di base. Le differenze tra maiuscole (maiuscole e minuscole), sono tipicamente ignorate, se vi sono differenze nella base o negli accenti. La punteggiatura è variabile. In alcune situazioni un carattere di punteggiatura è trattato come un carattere di base. Nelle altre situazioni , deve essere ignorato se ci sono differenze di base, accent o case . Potrebbe anche esserci un finale, livello di tie-break, per cui se non ci sono altre differenze nella stringa, viene utilizzato l'ordine del punto (normalizzato) .

Quindi "Munt ..." e "Münc ..." sono alfabeticamente diversi e ordinati in base a "t" e "c".

considerando che, "mun" e "Mün" sono in ordine alfabetico la stessa (equivelent "u" per "ü" in lingue perdute) in modo che i codici di caratteri vengono confrontati

6

Sembra che il carattere accentato sia utilizzato solo in una sorta di situazione di "tie-break" - in altre parole, se le stringhe sono uguali.

Ecco alcuni esempi di codice per dimostrare: (. Ho provato ad aggiungere uno spazio dopo la "n", così, per vedere se è stato fatto su confini di parola - non è)

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

Risultati:

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

ho il sospetto che questo sia corretto da varie regole complicate Unicode - ma io non ne so abbastanza su di loro.

Per quanto riguarda se è necessario tenerne conto ... non me lo aspetterei. Che cosa stai facendo è gettato da questo?

4

Come ho capito questo è ancora un po 'coerente. Quando si confronta usando CultureInfo.InvariantCulture il carattere di umlaut ü viene considerato come il carattere non accentato u.

Poiché le stringhe nel primo esempio ovviamente non sono uguali, il risultato non sarà 0 ma -1 (che sembra essere un valore predefinito). Nel secondo esempio Muntelier è valido perché t segue c nell'alfabeto.

non ho potuto trovare alcuna documentazione chiara in MSDN che spiega queste regole, ma ho scoperto che

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

e

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

dà il risultato desiderato.

In ogni caso, penso che sarebbe meglio basare il tuo ordinamento su una cultura specifica come la cultura dell'utente corrente (se possibile).

+0

'CompareOptions.Ordinal' potrebbe anche essere un'opzione. Con questa opzione le stringhe verranno confrontate in base ai valori Unicode. Vedi http://msdn.microsoft.com/en-us/library/system.globalization.compareoptions.aspx. –

Problemi correlati