54 votes

Les comparaisons de chaînes pourraient-elles vraiment différer en fonction de la culture lorsque la chaîne est garantie de ne pas changer?

Je lis des informations d'identification / chaînes de connexion chiffrées à partir d'un fichier de configuration. Resharper me dit que "String.IndexOf (string) est spécifique à la culture ici" sur cette ligne:

 if (line.Contains("host=")) {
    _host = line.Substring(line.IndexOf(
        "host=") + "host=".Length, line.Length - "host=".Length);
 

... et veut donc le changer pour:

 if (line.Contains("host=")) {
    _host = line.Substring(line.IndexOf("host=", System.StringComparison.Ordinal) + "host=".Length, line.Length -   "host=".Length);
 

La valeur que je lis sera toujours "hôte =", quel que soit l'endroit où l'application peut être déployée. Est-ce vraiment judicieux d'ajouter ce bit "System.StringComparison.Ordinal"?

Plus important encore, cela pourrait-il blesser quelque chose (l'utiliser)?

66voto

Mark Sowul Points 4249

Absolument. Par MSDN (http://msdn.microsoft.com/en-us/library/d93tkzah.aspx),

Cette méthode effectue un mot (sensible à la casse et sensible à la culture) recherche à l'aide de la culture actuelle.

De sorte que vous pouvez obtenir des résultats différents si vous l'exécutez en vertu d'une autre culture (via les paramètres régionaux et linguistiques dans le Panneau de Contrôle).

Dans ce cas particulier, vous n'aurez probablement pas un problème, mais jeter un i dans la chaîne de recherche et de l'exécuter en Turquie et il sera probablement ruiner votre journée.

Voir MSDN: http://msdn.microsoft.com/en-us/library/ms973919.aspx

Ces nouvelles recommandations et il existe des Api pour atténuer les hypothèses infondées sur le comportement de la chaîne par défaut Api. L'canonique exemple de bugs émergents où le non-linguistique chaîne de données est interprété linguistique est le "turc-je" problème.

Pour presque tous les alphabets latins, y compris l'anglais des états-UNIS, le caractère i (\u0069) est la version minuscule personnage, je (\u0049). Cette boîtier règle devient rapidement la valeur par défaut pour quelqu'un de la programmation en une telle culture. Toutefois, en turc ("tr-TR"), il existe un capital "je avec un point, le" caractère (\u0130), qui est la capitale de la version de j'. De même, en turc, il y a une minuscule "i sans point," ou (\u0131), qui capitalise à I. Ce comportement se produit dans l'Azéri la culture ("az") ainsi.

Par conséquent, les hypothèses sont normalement fabriqués à propos de capitaliser i ou mettre en minuscule je ne sont pas valides entre toutes les cultures. Si la valeur par défaut surcharges pour la comparaison de chaînes routines sont utilisées, elles seront sous réserve de la variance entre les cultures. Pour les non-linguistiques de données, comme dans l'exemple suivant, ce qui peut produire des résultats indésirables:

    Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")
Console.WriteLine("Culture = {0}",
   Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}", 
   (String.Compare("file", "FILE", true) == 0));

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
Console.WriteLine("Culture = {0}",
   Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}", 
   (String.Compare("file", "FILE", true) == 0));

En raison de la différence de la comparaison de I, les résultats de l' comparaisons changer lorsque le fil de culture est changé. C'est le sortie:

Culture = English (United States)
(file == FILE) = True
Culture = Turkish (Turkey)
(file == FILE) = False

Voici un exemple sans cas:

var s1 = "é"; //é as one character (ALT+0233)
var s2 = "é"; //'e', plus combining acute accent U+301 (two characters)

Console.WriteLine(s1.IndexOf(s2, StringComparison.Ordinal)); //-1
Console.WriteLine(s1.IndexOf(s2, StringComparison.InvariantCulture)); //0
Console.WriteLine(s1.IndexOf(s2, StringComparison.CurrentCulture)); //0

27voto

m-y Points 12871

CA1309: UseOrdinalStringComparison

Il n'a pas de mal à ne pas l'utiliser, mais "en définissant explicitement le paramètre pour le StringComparison.Ordinale ou StringComparison.OrdinalIgnoreCase, votre code permet souvent de gagner de la vitesse, augmente l'exactitude, et devient de plus en plus fiables.".


Qu'est-ce exactement est Ordinale, et pourquoi est-il important pour votre cas?

Une opération qui utilise ordinale règles de tri effectue une comparaison basée sur la valeur numérique (point de code Unicode) de chaque caractère dans la chaîne. Une comparaison ordinale est rapide mais la culture est insensible à la casse. Lorsque vous utilisez ordinal règles de tri pour trier les chaînes qui commencent par les caractères Unicode (U+), la chaîne de caractères U+xxxx vient avant la chaîne de caractères U+aaaa si la valeur de xxxx est numériquement inférieure aaaa.

Et, comme vous l'avez dit... la chaîne de valeur de la lecture n'est pas la culture sensible, il est donc logique d'utiliser une comparaison Ordinale, par opposition à un Mot de comparaison. Rappelez-vous juste, Ordinale, signifie "ce n'est pas la culture sensible".

7voto

Pour répondre à votre question spécifique: non, mais un outil d'analyse statique ne pourra pas se rendre compte que votre valeur d'entrée ne contiendra jamais d'informations spécifiques à l'environnement local.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X