Existe-t-il un opérateur égal insensible à la casse C #?


156

Je sais que ce qui suit est sensible à la casse:

if (StringA == StringB) {

Y a-t-il donc un opérateur qui comparera deux chaînes de manière insensible?



Au cas où quelqu'un trébucherait sur cette question à la recherche d'une comparaison insensible à la casse pour un dictionnaire <string, int>, jetez un œil à cette question ici: Accès insensible à la casse pour le dictionnaire générique
Robotnik

Ce serait vraiment sympa; disons de définir un correspondant ~=à parallèle ==comme une version insensible à la casse.
eidylon le

Si les développeurs Microsoft voient cela, je pense qu'il est nécessaire d'utiliser un opérateur insensible à la casse dans la prochaine version de csharp. Cette chaîne.Equal () est longue.
Rez.Net

Réponses:


288

Essaye ça:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);

Je suis un débutant relatif à StackOverflow - pouvez-vous expliquer ce que vous entendez en ajoutant un lien? Voulez-vous dire aux documents MSDN?
John Feminella

55
Si vous souhaitez une comparaison sensible à la culture, utilisez cette méthode. Si vous voulez juste vous assurer que "FILE" et "file" sont tous les deux acceptés, utilisez "OrdinalIgnoreCase" ou votre code pourrait ne pas fonctionner dans des endroits comme les paramètres régionaux turcs. Pour plus d'informations, voir moserware.com/2008/02/does-your-code-pass-turkey-test.html
Jeff Moser

10
Je ne sais pas de quoi Samuel parle ... cette réponse est parfaite. C'est correct et explicite. Il n'a besoin d'aucune référence. +1
Sailing Judo

3
Argh c'est une bouchée horrible! mon clavier s'usera. Fini le temps où je peux utiliser " if A$=B$ then goto 10"
Sanjay Manohar

9
@Sanjay Manohar Ensuite, écrivez un opérateur personnalisé - et je recommanderais un meilleur clavier.
Rushyo

37

La meilleure façon de comparer 2 chaînes en ignorant la casse des lettres est d'utiliser la méthode statique String.Equals en spécifiant une comparaison de chaîne ordinale ignorant la casse. C'est aussi le moyen le plus rapide, beaucoup plus rapide que de convertir les chaînes en minuscules ou majuscules et de les comparer ensuite.

J'ai testé les performances des deux approches et la comparaison des chaînes ordinales ignorées était plus de 9 fois plus rapide ! Il est également plus fiable que la conversion de chaînes en minuscules ou majuscules (consultez le problème turc i). Utilisez donc toujours la méthode String.Equals pour comparer les chaînes pour l'égalité:

String.Equals(string1, string2, StringComparison.OrdinalIgnoreCase);

Si vous souhaitez effectuer une comparaison de chaînes spécifiques à une culture, vous pouvez utiliser le code suivant:

String.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase);

Veuillez noter que le deuxième exemple utilise la logique de comparaison de chaînes de la culture actuelle, ce qui la rend plus lente que la comparaison "ordinal ignore case" dans le premier exemple, donc si vous n'avez pas besoin d'une logique de comparaison de chaînes spécifique à la culture et que vous êtes après des performances maximales, utilisez la comparaison «ordinal ignorer la casse».

Pour plus d'informations, lisez l'histoire complète sur mon blog .


1
Ne suggérez pas ToLowerou ToLowerInvariant: ils créent de la mémoire juste pour effectuer une comparaison, et ils peuvent échouer lorsque de nouveaux jeux de caractères sont ajoutés à l'Unicode. ToUpperéchoue à cause du «i» turc, entre autres; il n'y a aucune raison de ToLowerne pas échouer à l'avenir pour des raisons similaires.
antiduh

@antiduh, merci pour ton commentaire. La plupart d'entre nous sont conscients de ces problèmes potentiels, de nombreux tutoriels sur Internet donnent l'exemple du «i» turc. Comme vous le voyez dans mon article, je ne recommande pas l'utilisation de méthodes ToLowerou ToLowerInvariant, je voulais juste montrer à quel point la String.Equalsméthode est plus efficace .
Pavel Vladov

3
"La plupart d'entre nous sont conscients de ces problèmes potentiels, de nombreux tutoriels sur Internet donnent l'exemple du" i "turc" - il n'y a pas assez de gens, et vous le mentionnez toujours comme deuxième phrase de votre réponse. De plus, votre réponse n'inclut pas suffisamment de justification pour ne jamais l'utiliser - vous mentionnez simplement la performance; la performance n'est pas toujours la priorité absolue. Par conséquent, vous enfreignez actuellement les consignes du centre d'aide. les liens vers des sites externes sont corrects, mais vous n'avez pas suffisamment résumé le contenu (problème du «i» turc). SO n'est pas votre plateforme publicitaire.
antiduh

20

Il existe un certain nombre de propriétés sur la StringComparerclasse statique qui renvoient des comparateurs pour tout type de sensibilité à la casse que vous pourriez souhaiter:

StringComparer Propriétés

Par exemple, vous pouvez appeler

StringComparer.CurrentCultureIgnoreCase.Equals(string1, string2)

ou

StringComparer.CurrentCultureIgnoreCase.Compare(string1, string2)

C'est un peu plus propre que les surcharges string.Equalsou string.Comparequi prennent un StringComparisonargument.


15
System.Collections.CaseInsensitiveComparer

ou

System.StringComparer.OrdinalIgnoreCase

Cela affecte-t-il l'ensemble de l'application?
GateKiller

3
Où puis-je trouver plus d'informations à ce sujet. Cela signifie-t-il que je peux utiliser == pour une correspondance insensible à la casse?
GateKiller

9
string.Equals(StringA, StringB, StringComparison.CurrentCultureIgnoreCase);

8

ou

if (StringA.Equals(StringB, StringComparison.CurrentCultureIgnoreCase)) {

mais vous devez vous assurer que StringA n'est pas nul. Il vaut donc probablement mieux utiliser:

string.Equals(StringA , StringB, StringComparison.CurrentCultureIgnoreCase);

comme John l'a suggéré

EDIT: correction du bug


4

Vous pouvez utiliser

if (stringA.equals(StringB, StringComparison.CurrentCultureIgnoreCase))

3

Opérateur? NON, mais je pense que vous pouvez changer votre culture afin que la comparaison de chaînes ne soit pas sensible à la casse.

// you'll want to change this...
System.Threading.Thread.CurrentThread.CurrentCulture
// and you'll want to custimize this
System.Globalization.CultureInfo.CompareInfo

Je suis convaincu que cela changera la façon dont les chaînes sont comparées par l'opérateur égal.


Ouais, c'est le moins que l'on puisse dire, ce n'est absolument pas ce que vous voudriez faire à moins que vous ne vouliez que toutes les comparaisons de chaînes soient insensibles à la casse. Mais je pense que cela change le comportement de l'opérateur égal.
John Leidegren

3

Voici une idée pour simplifier la syntaxe:

public class IgnoreCase
{
    private readonly string _value;

    public IgnoreCase(string s)
    {
        _value = s;
    }

    protected bool Equals(IgnoreCase other)
    {
        return this == other;
    }

    public override bool Equals(object obj)
    {
        return obj != null &&
               (ReferenceEquals(this, obj) || (obj.GetType() == GetType() && this == (IgnoreCase) obj));
    }

    public override int GetHashCode()
    {
        return _value?.GetHashCode() ?? 0;
    }

    public static bool operator ==(IgnoreCase a, IgnoreCase b)
    {
        return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
    }

    public static bool operator !=(IgnoreCase a, IgnoreCase b)
    {
        return !(a == b);
    }

    public static implicit operator string(IgnoreCase s)
    {
        return s._value;
    }

    public static implicit operator IgnoreCase(string s)
    {
        return new IgnoreCase(s);
    }
}

Utilisable comme:

Console.WriteLine((IgnoreCase) "a" == "b"); // false
Console.WriteLine((IgnoreCase) "abc" == "abC"); // true
Console.WriteLine((IgnoreCase) "Abc" == "aBc"); // true
Console.WriteLine((IgnoreCase) "ABC" == "ABC"); // true

Alors que j'aime le propre recherche la syntaxe d'utilisation, il est un peu trompeur ( IgnoreCasevs IgnoreCaseString) et ambiguë (Java prend unboxing implicite vs boxe implicite , donc je crois que cela ne fonctionnerait pas en Java avec le dos coulé implicite à chaîne là - dedans). Et cela crée la surcharge de mémoire de 2 nouveaux objets avec l'exécution de l'arborescence des appels pour chaque comparaison sautant dans plusieurs appels de méthode imbriqués pour le cas d'utilisation affiché. Cela dit, dans la plupart des cas, les performances sont probablement assez bonnes.
Arkaine55

Bien que ce soit une idée intelligente , ce n'est pas vraiment judicieux du point de vue de la maintenabilité. Vous créez effectivement un type de chaîne de substitution au lieu d'utiliser le type de chaîne intégré au système. Le programmeur-qui-vient-après ne comprendra pas ce qui se passe en un coup d'œil et ensuite il / elle vous insultera. Utiliser string.Equals () n'est pas vraiment si mal et la plupart des gens comprendront ce que cela fait.
ntcolonel

1

Je suis tellement habitué à taper à la fin de ces méthodes de comparaison: , StringComparison.

J'ai donc fait une extension.

namespace System
{   public static class StringExtension
    {
        public static bool Equals(this string thisString, string compareString,
             StringComparison stringComparison)
        {
            return string.Equals(thisString, compareString, stringComparison);
        }
    }
}

Notez simplement que vous devrez vérifier la valeur null sur thisStringavant d'appeler le poste.


1
Est-ce la même chose que cette méthode intégrée dans les versions actuelles du .NET Framework? docs.microsoft.com/en-gb/dotnet/api/…
Bernard Vander Beken

1
Apparaît ainsi. Il semble que les versions ultérieures de .net incluent maintenant cela.
Valamas

Disponible depuis .NET 4.5 et toutes les versions .NET Core.
Bernard Vander Beken


0
if (StringA.ToUpperInvariant() == StringB.ToUpperInvariant()) {

Les gens rapportent que ToUpperInvariant () est plus rapide que ToLowerInvariant ().


1
Invariant peut être une mauvaise idée si la culture actuelle ou souhaitée a des règles spéciales pour les majuscules.
OregonGhost

Cela crée-t-il une nouvelle copie de chaque chaîne? Si c'est le cas, mauvaise idée.
cjk

1
Cela lèvera également une exception si l'une des chaînes (ou les deux) est nulle.
tvanfosson

3
En termes de performances, ce n'est pas une si bonne solution car vous allez également créer 2 nouvelles instances de chaîne ici.
Frederik Gheysels

0

D'autres réponses sont totalement valables ici, mais d'une manière ou d'une autre, il faut un certain temps pour taper StringComparison.OrdinalIgnoreCaseet utiliserString.Compare .

J'ai codé la méthode d'extension de chaîne simple, dans laquelle vous pouvez spécifier si la comparaison est sensible à la casse ou à la casse avec booléen - voir la réponse suivante:

https://stackoverflow.com/a/49208128/2338477

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.