Comment puis-je faire une comparaison de chaînes insensible à la casse?

217

Comment puis-je rendre la ligne ci-dessous insensible à la casse?

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username == (string)drUser["Username"]) != -1);

Plus tôt dans la journée, j'ai reçu des conseils qui m'ont suggéré d'utiliser:

x.Username.Equals((string)drUser["Username"], StringComparison.OrdinalIgnoreCase)));

le problème est que je ne peux pas faire fonctionner cela, j'ai essayé la ligne ci-dessous, cela compile mais renvoie les mauvais résultats, il renvoie les utilisateurs inscrits comme non inscrits et les utilisateurs non inscrits comme inscrits.

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username.Equals((string)drUser["Username"], 
                                 StringComparison.OrdinalIgnoreCase)));

Quelqu'un peut-il signaler le problème?

Jamie
la source
1
Quel type de données doit drUser["Enrolled"]être? Il ressemble à une valeur booléenne, mais FindIndex()renvoie l'index. Si l'index de cet utilisateur est 0, il retournera 0, ce qui peut être faux. Quand, en réalité, c'est vrai. La Exists()méthode peut être meilleure dans ce cas.
drharris
Êtes-vous sûr qu'il n'y a pas de temps de mise en forme ou d'espace supplémentaire dans un champ qui n'est pas dans l'autre?
joshlrogers
1
Je suggère d'utiliser registredUsers.Any () au lieu de FindIndex (et test).
Marc

Réponses:

405

Ce n'est pas la meilleure pratique dans .NET Framework (4 & +) pour vérifier l'égalité

String.Compare(x.Username, (string)drUser["Username"], 
                  StringComparison.OrdinalIgnoreCase) == 0

Utilisez plutôt ce qui suit

String.Equals(x.Username, (string)drUser["Username"], 
                   StringComparison.OrdinalIgnoreCase) 

MSDN recommande:

  • Utilisez une surcharge de la méthode String.Equals pour tester si deux chaînes sont égales.
  • Utilisez les méthodes String.Compare et String.CompareTo pour trier les chaînes, pas pour vérifier l'égalité .
ocean4dream
la source
8
Vous devez utiliser string.Compare, non String.Compare.
Fred
5
@Fred Je suis d'accord mais pouvez-vous qualifier la raison?
Gusdor
22
@Fred J'espérais pour une raison technique plutôt que «parce que Stylecop le dit». Suis-je en train de manquer quelque chose?
Gusdor
12
aucune différence string.compare avec String.Compare, synonymes de chaîne System.String classe. et Member Compare est une méthode d'extension. @ Fred @Gusdor
Nuri YILMAZ
23
@Gusdor stringest une meilleure pratique que Stringpuisqu'il s'agit d'un mot-clé de langue. D'une part, Stringpourrait être autre chose que System.String, alors stringqu'il ne peut pas l'être. En outre, il stringest plus ou moins garanti d'exister en C #, alors qu'il Stringfait techniquement partie de .NET plutôt que C #.
Dave Cousineau
36

Vous devez utiliser une String.Comparefonction statique comme suit

x => String.Compare (x.Username, (string)drUser["Username"],
                     StringComparison.OrdinalIgnoreCase) == 0
Oleg
la source
6
Non, vous devez utiliser à la String.Equalsplace de String.Compare. Il n'est pas nécessaire de calculer lequel est le plus grand, juste qu'ils ne sont pas égaux.
ErikE
@ErikE: Je me demande quelle méthode vous recommanderez d'utiliser dans 6 ans de plus :-)
Oleg
3
Je ne me demande pas! Je suis convaincu que je recommanderai d'utiliser l'égalité lorsque vous voulez une sémantique d'égalité et d'utiliser la comparaison lorsque vous voulez une sémantique de comparaison. Qu'est-ce qui est si difficile? IEquatableet IComparablene faites PAS la même chose, et vous pouvez avoir des classes qui implémentent l'une mais dans lesquelles cela n'aurait aucun sens d'implémenter l'autre. Par exemple, vous pouvez commander des échantillonnages de capteurs dans le temps sans qu'aucun d'entre eux ne soit égal (IComparable). Et, vous pouvez indiquer si les choses sont égales (IEquatable) mais cela n'a aucun sens de les commander (par exemple, les numéros de série des ordinateurs).
ErikE
@ErikE: Vous ne comprenez pas mon point de vue. Les anciennes réponses correspondent au moment de l'écriture. Il ne faut pas toucher aux vieilles réponses. C'est vrai pour la plupart des produits. La meilleure pratique ou le meilleur choix du point de vue des performances peuvent être modifiés plusieurs fois par la suite. Je ne vois aucun sens à discuter d'une ancienne réponse.
Oleg
18
Mes excuses, je l'ai pris comme une critique sur l'exactitude de mon commentaire. Si vous dites que vous admettez que votre ancienne réponse n'est peut-être pas la meilleure, alors tant mieux! Cependant, je dois être en désaccord avec vous sur les anciennes réponses. Les vieilles réponses qui donnent des informations médiocres devraient être commentées, devraient être rejetées, car elles informent encore les lecteurs d'aujourd'hui .
ErikE
27

Veuillez utiliser ceci pour la comparaison:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);
Gautam Kumar Sahu
la source
10
Soyez simplement conscient des avantages et des pièges de l'utilisation de CurrentCultureIgnoreCase par rapport à OrdinalIgnoreCase. Si vous n'avez pas besoin de la sémantique de la comparaison des cultures, enregistrez des performances et utilisez la comparaison ordinale.
ErikE
7

D'autres réponses sont totalement valables ici, mais d'une manière ou d'une autre, cela prend un certain temps pour taper StringComparison.OrdinalIgnoreCaseet également utiliser String.Compare.

J'ai codé une méthode d'extension de chaîne simple, où vous pouvez spécifier si la comparaison est sensible à la casse ou insensée à la valeur booléenne, en attachant un extrait de code entier ici:

using System;

/// <summary>
/// String helpers.
/// </summary>
public static class StringExtensions
{
    /// <summary>
    /// Compares two strings, set ignoreCase to true to ignore case comparison ('A' == 'a')
    /// </summary>
    public static bool CompareTo(this string strA, string strB, bool ignoreCase)
    {
        return String.Compare(strA, strB, ignoreCase) == 0;
    }
}

Après que toute la comparaison se raccourcisse de 10 caractères environ - comparez:

Avant d'utiliser l'extension String:

String.Compare(testFilename, testToStart,true) != 0

Après avoir utilisé l'extension String:

testFilename.CompareTo(testToStart, true)
TarmoPikaro
la source
2
Je ne suis pas d'accord avec la dénomination, comparer est une fonction bien connue dans le développement de logiciels et vous avez fondamentalement changé ce qu'il fait. Je pense que vous devriez soit retourner un int comme comparer ou changer le nom en quelque chose d'autre, 'IsEqual' par exemple.
Fred
7

Vous pouvez (bien que controversé) étendre System.Stringpour fournir une méthode d'extension de comparaison insensible à la casse:

public static bool CIEquals(this String a, String b) {
    return a.Equals(b, StringComparison.CurrentCultureIgnoreCase);
}

et utiliser comme tel:

x.Username.CIEquals((string)drUser["Username"]);

C # vous permet de créer des méthodes d'extension qui peuvent servir de syntaxe au sucre dans votre projet, je dirais plutôt utile.

Ce n'est pas la réponse et je sais que cette question est ancienne et résolue, je voulais juste ajouter ces bits.

Felype
la source
3

Je pense que vous trouverez plus d'informations dans ce lien:

http://codeidol.com/community/dotnet/controlling-case-sensitivity-when-comparing-two-st/8873/

Utilisez la méthode Compare static sur la classe String pour comparer les deux chaînes. Le fait que la comparaison soit insensible à la casse est déterminé par le troisième paramètre de l'une de ses surcharges. Par exemple:

string lowerCase = "abc";
string upperCase = "AbC";
int caseInsensitiveResult = string.Compare(lowerCase, upperCase,
  StringComparison.CurrentCultureIgnoreCase);
int caseSensitiveResult = string.Compare(lowerCase,
  StringComparison.CurrentCulture);

La valeur caseSensitiveResult est -1 (indiquant que lowerCase est "inférieur à" upperCase) et le caseInsensitiveResult est zéro (indiquant que lowerCase "est égal" à upperCase).

i_thamary
la source
1

Je voudrais écrire une méthode d'extension pour EqualsIgnoreCase

public static class StringExtensions
{
    public static bool? EqualsIgnoreCase(this string strA, string strB)
    {
        return strA?.Equals(strB, StringComparison.CurrentCultureIgnoreCase);
    }
}
Ranga
la source
-11

vous pouvez toujours utiliser des fonctions: .ToLower (); .ToUpper ();

convertissez vos chaînes puis comparez-les ...

Bonne chance

user3895427
la source
Je ne pense pas que cela résoudrait son problème. Notez également que cette question a déjà plus de 4 ans.
Vojtěch Dohnal
7
Cela crée une nouvelle chaîne, donc je considère cela très inefficace. Parce que pour créer cette nouvelle chaîne, tous les caractères seront vérifiés et convertis dans le cas souhaité, alors la comparaison doit vérifier à nouveau tous les caractères. Il utilise donc plus de mémoire et de puissance de traitement.
Air2
5
Il s'agit d'une très mauvaise pratique en raison de l'allocation de mémoire.
Thorbjørn Lindeijer
Non seulement cela est une allocation de mémoire inutile et inefficace; il échoue également au test de la Turquie .
dmitry