Perché string.Compare sembra per gestire i caratteri accentati incoerente?
-
21-09-2019 - |
Domanda
Se eseguo la seguente dichiarazione:
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)
I get '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 accentato
Il motivo per cui questo è un problema è, sto ordinamento di un elenco e poi fare un filtro binario manuale che è destinata ad ottenere ogni stringa che inizia con 'xxx'.
In precedenza stavo usando il metodo 'Dove' LINQ, 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 qualunque regole 'unicode' NET ha. Quindi, se gli dico di filtrare per 'Mün', non trova nessun articolo, anche se ci sono voci nell'elenco che iniziano con 'mun'.
Questo sembra essere a causa del l'ordinamento incoerente di caratteri accentati, a seconda di quali caratteri andare dopo il carattere accentato.
OK, credo di aver risolto il problema.
Prima del filtro, faccio una specie sulla base del primo n lettere di ogni stringa, dove n è la lunghezza della stringa di ricerca.
Soluzione
C'è un algoritmo di spareggio sul posto di lavoro, vedi http://unicode.org/reports/tr10/
Per affrontare la complessità della sensibile alla lingua ordinamento, un algoritmo di confronto multilivello impiegato. Nel confronto tra due parole, per ad esempio, la caratteristica più importante è il carattere di base: come la differenza tra una A e una B. differenze di accento sono in genere ignorata, se ci sono delle differenze le lettere di base. differenze caso (Maiuscolo contro minuscolo), sono tipicamente ignorata, se ce ne sono differenze nella base o accenti. La punteggiatura è variabile. In qualche situazioni un carattere di punteggiatura è trattata come un carattere di base. Nel altre situazioni, si dovrebbe essere ignorato se ci sono qualsiasi base, accento, o caso differenze. Ci può essere anche un finale, tie-breaking livello, per cui se non ci sono altre differenze a tutti nella stringa, il codice (normalizzata) ordine punto viene utilizzato.
Quindi, "Munt ..." e "... Munc" sono in ordine alfabetico diverso e basato sul tipo "t" e "c".
considerando che, "mun" e "Mün" sono in ordine alfabetico lo stesso ( "u" equivelent a "ü" in lingue perdute) in modo che i codici di caratteri vengono confrontati
Altri suggerimenti
Sembra che il carattere accentato è utilizzato solo in una sorta di situazione di "tie-break" - in altre parole, se le stringhe sono uguali altrimenti
.Ecco alcuni esempi di codice per dimostrare:
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);
}
}
(Ho provato ad aggiungere uno spazio dopo la "n", così, per vedere se è stato fatto su confini di parola -. Non lo è)
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 non so abbastanza su di loro
.Per quanto riguarda se è necessario tener conto di questo ... non mi aspetto così. Che cosa stai facendo che è gettato da questo?
A quanto ho capito questo, è ancora un po 'coerente. Quando si confrontano utilizzando CultureInfo.InvariantCulture
il carattere ü
dieresi viene trattato come il u
non accentato carattere.
Come le corde nel primo esempio, ovviamente, non sono uguali il risultato non sarà 0 ma -1 (che sembra essere un valore di default). Nel secondo esempio, Muntelier va ultimo perché t segue c in 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 la vostra ordinamento su una cultura specifica, come la cultura dell'utente corrente (se possibile).