Quel est généralement préférable d'utiliser - StringComparison.OrdinalIgnoreCase ou StringComparison.InvariantCultureIgnoreCase?

162

J'ai un code comme celui-ci:

If key.Equals("search", StringComparison.OrdinalIgnoreCase) Then
    DoSomething()
End If

Je me fiche de l'affaire. Dois - je utiliser OrdinalIgnoreCase, InvariantCultureIgnoreCaseou CurrentCultureIgnoreCase?

Dave Haynes
la source
2
Vérifiez ceci, c'est vraiment utile pour ce fil. Ma suggestion d'utiliser ordianlignorecase pour comparaison. blogs.msdn.com/b/noahc/archive/2007/06/29/…
UmaMaheswaran
Considérez la réponse hautement votée de la comparaison de chaînes en
Michael Freidgeim
Dans l'ensemble, cela dépend beaucoup du type de chose que vous comparez. Plus précisément, s'il s'agit d'une entrée utilisateur dépendante de la culture ou d'un élément interne. Vous ne voulez pas que la culture du PC gâche les comparaisons de chaînes de code internes.
Nyerguds

Réponses:

180

Les nouveaux documents .Net ont désormais un tableau pour vous aider à décider lequel est le mieux à utiliser dans votre situation.

Extrait des « Nouvelles recommandations pour l'utilisation de chaînes dans Microsoft .NET 2.0 » de MSDN

Résumé: Les propriétaires de code utilisant précédemment InvariantCulturepour la comparaison de chaînes, la casse et le tri doivent fortement envisager d'utiliser un nouvel ensemble de Stringsurcharges dans Microsoft .NET 2.0. Plus précisément, les données qui est conçu pour être la culture agnostique et linguistiquement non pertinentes devraient commencer spécifier en utilisant soit le surcharge StringComparison.Ordinalou les StringComparison.OrdinalIgnoreCasemembres du nouveauStringComparison énumération. Ceux-ci imposent une comparaison octet par octet similaire à strcmpcelle qui évite non seulement les bogues d'interprétation linguistique de chaînes essentiellement symboliques, mais offre de meilleures performances.

Robert Taylor
la source
126
Pour donner un exemple où ils diffèrent, considérez les deux chaînes "Straße"et "STRASSE". Lors de l'utilisation OrdinalIgnoreCasedes Equalsretours false, alors que InvariantCultureIgnoreCasedit qu'ils sont égaux.
Jeppe Stig Nielsen
2
Lien mis à jour: docs.microsoft.com/en-us/dotnet/standard/base-types/…
Ohad Schneider
64

Tout dépend

La comparaison des chaînes Unicode est difficile:

La mise en œuvre des recherches et comparaisons de chaînes Unicode dans les logiciels de traitement de texte doit prendre en compte la présence de points de code équivalents. En l'absence de cette fonctionnalité, les utilisateurs recherchant une séquence de points de code particulière seraient incapables de trouver d'autres glyphes visuellement indiscernables qui ont une représentation de point de code différente, mais canoniquement équivalente.

voir: http://en.wikipedia.org/wiki/Unicode_equivalence


Si vous essayez de comparer 2 chaînes Unicode de manière insensible à la casse et que vous souhaitez que cela fonctionne PARTOUT , vous avez un problème impossible.

L'exemple classique est le turc je , qui lorsqu'il est mis en majuscule devient İ (notez le point)

Par défaut, le framework .Net utilise généralement la CurrentCulture pour les fonctions liées aux chaînes, avec une exception très importante .Equalsqui utilise une comparaison ordinale (octet par octet).

Cela conduit, de par sa conception, à ce que les différentes fonctions de chaîne se comportent différemment selon la culture de l'ordinateur.


Néanmoins, nous voulons parfois une comparaison «à usage général», insensible à la casse.

Par exemple, vous souhaiterez peut-être que votre comparaison de chaînes se comporte de la même manière, quel que soit l'ordinateur sur lequel votre application est installée.

Pour y parvenir, nous avons 3 options:

  1. Définissez la culture explicitement et effectuez une comparaison insensible à la casse à l'aide de règles d'équivalence Unicode.
  2. Définissez la culture sur la culture invariante et effectuez une comparaison insensible à la casse à l'aide de règles d'équivalence unicode.
  3. Utilisez OrdinalIgnoreCase qui mettra en majuscule la chaîne à l'aide de InvariantCulture, puis effectuera une comparaison octet par octet.

Les règles d'équivalence Unicode sont compliquées, ce qui signifie que l'utilisation de la méthode 1) ou 2) est plus coûteuse que OrdinalIgnoreCase. Le fait que OrdinalIgnoreCasecela n'effectue aucune normalisation Unicode spéciale signifie que certaines chaînes qui sont rendues de la même manière sur un écran d'ordinateur ne seront pas considérées comme identiques. Par exemple: "\u0061\u030a"et les "\u00e5"deux rendent å. Cependant, une comparaison ordinale sera considérée comme différente.

Le choix que vous choisissez dépend fortement de l'application que vous créez.

  • Si j'écrivais une application métier qui n'était utilisée que par les utilisateurs turcs, je serais sûr d'utiliser la méthode 1.
  • Si j'avais juste besoin d'une simple "fausse" comparaison insensible à la casse, par exemple un nom de colonne dans une base de données, qui est généralement en anglais, j'utiliserais probablement la méthode 3.

Microsoft a son ensemble de recommandations avec des directives explicites. Cependant, il est vraiment important de comprendre la notion d'équivalence unicode avant d'aborder ces problèmes.

Aussi, gardez à l'esprit que OrdinalIgnoreCase est un type très spécial de bête, qui cueille et choisit un peu un ordinal comparé à certains aspects lexicographiques mixtes. Cela peut être déroutant.

Sam Safran
la source
Et si je construis une application turque qui ne sera utilisée que par les utilisateurs turcs mais que je veux que «ayakkabı» et «ayakkabi» soient égaux, y a-t-il un moyen? Lorsque les gens tapent sur leur téléphone, la plupart d'entre eux utilisent le clavier anglais par défaut et ne se soucient pas de savoir s'ils tapent "ı" ou "i".
Volkan Sen il y a
4

Je suppose que cela dépend de votre situation. Étant donné que les comparaisons ordinales examinent en fait les valeurs Unicode numériques des caractères, elles ne seront pas le meilleur choix lorsque vous triez par ordre alphabétique. Pour les comparaisons de chaînes, cependant, l'ordinal serait un peu plus rapide.

Bullines
la source
1

Cela dépend de ce que vous voulez, même si j'éviterais la culture invariante sauf si vous êtes très sûr que vous ne voudrez plus jamais localiser le code pour d' autres langues. Utilisez plutôt CurrentCulture.

En outre, OrdinalIgnoreCase doit respecter les nombres, qui peuvent ou non être ce que vous voulez.

Joël Coehoorn
la source
1
Avez-vous déjà écrit du code VB6 dans un environnement multilingue? Vous pouvez créer du code qui se compile sur un PC avec la locale française mais ne compilera pas sur les PC avec la locale anglaise, car tous les nombres stockés dans les ressources de formulaire utilisent le format de la locale actuelle. Je dirais que vous devez adopter l'approche opposée: soyez très prudent lorsque vous utilisez la culture actuelle. Pensez toujours à savoir si votre système fonctionnera toujours lorsque ses données se déplaceront entre les cultures. Même chose avec les fuseaux horaires.
Wim Coenen le
Je suis d'accord avec la réponse «ça dépend». mais ne pas suivre le bit "respecter les nombres"?
Sam Saffron
-1

La réponse très simple est que, sauf si vous utilisez le turc, vous n'avez pas besoin d'utiliser InvariantCulture.

Voir le lien suivant:

En C # quelle est la différence entre ToUpper () et ToUpperInvariant ()?

TheMoot
la source
5
Cette réponse est peut-être simple, mais elle est également très erronée. Le «je» turc n'est qu'un exemple , il existe de nombreux autres pièges possibles.
Ohad Schneider
Quels autres pièges? Je connais juste le cas du problème turc.
HelloWorld
Ouais, en plus du turc, il y a azéri. Mais c'est tout.
Jim Balter