Differenza tra InvariantCulture e confronto di stringhe ordinali

Quando si confrontano due stringhe in c # per l’uguaglianza, qual è la differenza tra InvariantCulture e confronto ordinale?

InvariantCulture

Utilizza un set “standard” di ordini di caratteri (a, b, c, … ecc.). Ciò è in contrasto con alcune impostazioni locali specifiche, che possono ordinare i caratteri in ordini diversi (‘a-with-acute’ può essere prima o dopo ‘a’, a seconda delle impostazioni internazionali e così via).

Ordinale

D’altra parte, guarda esclusivamente i valori dei byte grezzi che rappresentano il carattere.


C’è un ottimo esempio su http://msdn.microsoft.com/en-us/library/e6883c06.aspx che mostra i risultati dei vari valori StringComparison. Alla fine, mostra (estratto):

 StringComparison.InvariantCulture: LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131) LATIN SMALL LETTER I (U+0069) is less than LATIN CAPITAL LETTER I (U+0049) LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049) StringComparison.Ordinal: LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131) LATIN SMALL LETTER I (U+0069) is greater than LATIN CAPITAL LETTER I (U+0049) LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049) 

Potete vedere quello in cui guadagna InvariantCulture (U + 0069, U + 0049, U + 00131), Rendimenti ordinali (U + 0049, U + 0069, U + 00131).

Per esempio, importa – c’è una cosa chiamata espansione del personaggio

  var s1 = "Strasse"; var s2 = "Straße"; s1.Equals(s2, StringComparison.Ordinal); //false s1.Equals(s2, StringComparison.InvariantCulture); //true 

Con InvariantCulture il carattere ß viene espanso in ss.

Indicando le best practice per l’uso di stringhe in .NET Framework :

  • Usa StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase per i confronti come predefinito sicuro per la corrispondenza stringa indipendente dalla cultura.
  • Utilizza i confronti con StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase per prestazioni migliori.
  • Utilizzare i valori StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase non linguistici invece delle operazioni stringa basate su CultureInfo.InvariantCulture quando il confronto è linguisticamente irrilevante (ad esempio simbolico).

E infine:

  • Non utilizzare le operazioni con le stringhe basate su StringComparison.InvariantCulture nella maggior parte dei casi . Una delle poche eccezioni è quando si persistono dati linguisticamente significativi ma culturalmente agnostici.

Un’altra differenza pratica (in inglese, dove gli accenti sono rari) è che un confronto InvariantCulture confronta prima le intere stringhe per maiuscole e minuscole, e poi se necessario (e richiesto) si distingue per caso dopo aver prima confrontato solo le lettere distinte. (Si può anche fare un confronto insensibile alle maiuscole e minuscole, ovviamente, che non si distingue per caso.) Corretto: le lettere accentate sono considerate come un altro sapore delle stesse lettere e la stringa viene confrontata prima ignorando gli accenti e quindi calcolandoli se le lettere generali corrispondono tutte (molto come con casi diversi eccetto che alla fine ignorati in un confronto senza distinzione tra maiuscole e minuscole). Questo raggruppa le versioni accentate della stessa parola altrimenti vicine l’una all’altra invece che completamente separate alla prima differenza di accento. Questo è l’ordinamento che normalmente si trova in un dizionario, con le parole in maiuscolo che appaiono accanto ai loro equivalenti in minuscolo e le lettere accentate che si trovano vicino alla lettera non accentata corrispondente.

Un confronto ordinale confronta rigorosamente i valori numerici dei caratteri, fermandosi alla prima differenza. In questo modo le lettere maiuscole sono completamente separate dalle lettere minuscole (e le lettere accentate presumibilmente separate da quelle), quindi le parole in maiuscolo non si avvicinerebbero affatto ai loro equivalenti minuscoli.

InvariantCulture considera inoltre le maiuscole come maiuscole e minuscole, mentre Ordinal considera le maiuscole minuscole (un’ascesa di ASCII dai vecchi tempi prima che i computer avessero lettere minuscole, le lettere maiuscole venivano assegnate prima e quindi avevano valori inferiori rispetto alle lettere minuscole aggiunto in seguito).

Ad esempio, per Ordinal: "0" < "9" < "A" < "Ab" < "Z" < "a" < "aB" < "ab" < "z" < "Á" < "Áb" < "á" < "áb"

E di InvariantCulture: "0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"

L’invariante è un tipo di confronto linguisticamente appropriato.
Ordinal è un tipo di confronto binario. (Più veloce)
Vedi http://www.siao2.com/2004/12/29/344136.aspx

Sebbene la domanda riguardi l’ uguaglianza , per un rapido riferimento visivo, qui l’ordine di alcune stringhe è stato risolto usando un paio di culture che illustrano alcune delle idiosincrasie in circolazione.

 Ordinal 0 9 A Ab a aB aa ab ss Ä Äb ß ä äb ぁ あ ァ ア 亜 A IgnoreCase 0 9 a A aa ab Ab aB ss ä Ä äb Äb ß ぁ あ ァ ア 亜 A -------------------------------------------------------------------- InvariantCulture 0 9 a A A ä Ä aa ab aB Ab äb Äb ss ß ァ ぁ ア あ 亜IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ß ss ァ ぁ ア あ 亜-------------------------------------------------------------------- da-DK 0 9 a A A ab aB Ab ss ß ä Ä äb Äb aa ァ ぁ ア あ 亜IgnoreCase 0 9 A a A Ab aB ab ß ss Ä ä Äb äb aa ァ ぁ ア あ 亜-------------------------------------------------------------------- de-DE 0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜-------------------------------------------------------------------- en-US 0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜-------------------------------------------------------------------- ja-JP 0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜IgnoreCase 0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜 

osservazioni:

  • de-DE , ja-JP e en-US ordinano allo stesso modo
  • Invariant ordina solo ss e ß diverso rispetto alle tre culture precedenti
  • da-DK ordina in modo diverso
  • il flag IgnoreCase è importante per tutte le culture campionate

Il codice utilizzato per generare la tabella sopra:

 var l = new List { "0", "9", "A", "Ab", "a", "aB", "aa", "ab", "ss", "ß", "Ä", "Äb", "ä", "äb", "あ", "ぁ", "ア", "ァ", "A", "亜" }; foreach (var comparer in new[] { StringComparer.Ordinal, StringComparer.OrdinalIgnoreCase, StringComparer.InvariantCulture, StringComparer.InvariantCultureIgnoreCase, StringComparer.Create(new CultureInfo("da-DK"), false), StringComparer.Create(new CultureInfo("da-DK"), true), StringComparer.Create(new CultureInfo("de-DE"), false), StringComparer.Create(new CultureInfo("de-DE"), true), StringComparer.Create(new CultureInfo("en-US"), false), StringComparer.Create(new CultureInfo("en-US"), true), StringComparer.Create(new CultureInfo("ja-JP"), false), StringComparer.Create(new CultureInfo("ja-JP"), true), }) { l.Sort(comparer); Console.WriteLine(string.Join(" ", l)); } 

Ecco un esempio in cui il confronto dell’uguaglianza delle stringhe usando InvariantCultureIgnoreCase e OrdinalIgnoreCase non darà gli stessi risultati:

 string str = "\xC4"; //A with umlaut, Ä string A = str.Normalize(NormalizationForm.FormC); //Length is 1, this will contain the single A with umlaut character (Ä) string B = str.Normalize(NormalizationForm.FormD); //Length is 2, this will contain an uppercase A followed by an umlaut combining character bool equals1 = A.Equals(B, StringComparison.OrdinalIgnoreCase); bool equals2 = A.Equals(B, StringComparison.InvariantCultureIgnoreCase); 

Se esegui questo, equals1 sarà false e equals2 sarà true.

Non c’è bisogno di usare fancy unicode char exmaples per mostrare la differenza. Ecco un semplice esempio che ho scoperto oggi che è sorprendente, composto solo da caratteri ASCII.

Secondo la tabella ASCII, 0 (0x48) è più piccolo di _ (0x95) se confrontato ordinalmente. InvariantCulture direbbe il contrario (codice PowerShell di seguito):

 PS> [System.StringComparer]::Ordinal.Compare("_", "0") 47 PS> [System.StringComparer]::InvariantCulture.Compare("_", "0") -1 

Cerca sempre di utilizzare InvariantCulture in quei metodi stringa che lo accettano come sovraccarico. Usando InvariantCulture sei al sicuro. Molti programmatori .NET potrebbero non utilizzare questa funzionalità, ma se il tuo software verrà utilizzato da culture diverse, InvariantCulture è una funzionalità estremamente utile.