Insensible à la casse 'Contient (chaîne)'


2911

Existe-t-il un moyen de rendre le retour suivant vrai?

string title = "ASTRINGTOTEST";
title.Contains("string");

Il ne semble pas y avoir de surcharge qui me permette de régler la sensibilité à la casse. Actuellement, je les MAJUSCULE les deux, mais c'est juste idiot (par lequel je fais référence aux problèmes i18n qui viennent avec le boîtier de haut en bas).

MISE À JOUR
Cette question est ancienne et depuis lors, je me suis rendu compte que je demandais une réponse simple pour un sujet vraiment vaste et difficile si vous voulez bien l'enquêter.
Dans la plupart des cas, dans les bases de code monolingues et anglaises, cette réponse suffira. Je soupçonne que la plupart des gens qui viennent ici entrent dans cette catégorie, c'est la réponse la plus populaire.
Cette réponse soulève cependant le problème inhérent que nous ne pouvons pas comparer la casse insensible au texte jusqu'à ce que nous sachions que les deux textes sont la même culture et que nous savons ce que cette culture est. C'est peut-être une réponse moins populaire, mais je pense qu'elle est plus correcte et c'est pourquoi je l'ai marquée comme telle.

Réponses:


1398

Pour tester si la chaîne paragraphcontient la chaîne word(merci @QuarterMeister)

culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0

cultureest l'instance de CultureInfodescription de la langue dans laquelle le texte est écrit.

Cette solution est transparente quant à la définition de l'insensibilité à la casse, qui dépend du langage . Par exemple, la langue anglaise utilise les caractères Iet ipour les versions majuscules et minuscules de la neuvième lettre, tandis que la langue turque utilise ces caractères pour les onzième et douzième lettres de son alphabet de 29 lettres. La version turque des majuscules de «i» est le caractère inconnu «İ».

Ainsi, les chaînes tinet TINsont le même mot en anglais , mais des mots différents en turc . Si je comprends bien, l'un signifie «esprit» et l'autre est un mot onomatopée. (Turcs, veuillez me corriger si je me trompe, ou suggérer un meilleur exemple)

Pour résumer, vous ne pouvez répondre à la question `` ces deux chaînes sont-elles identiques mais dans des cas différents '' si vous savez dans quelle langue le texte est . Si vous ne savez pas, vous devrez prendre un botté de dégagement. Étant donné l'hégémonie de l'anglais dans les logiciels, vous devriez probablement y recourir CultureInfo.InvariantCulture, car ce sera faux de manière familière.


67
Pourquoi ne pas culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0? Cela utilise la bonne culture et est insensible à la casse, il n'alloue pas de chaînes minuscules temporaires, et cela évite la question de savoir si la conversion en minuscules et la comparaison sont toujours les mêmes qu'une comparaison insensible à la casse.
Quartermeister

9
Cette solution pollue également inutilement le tas en allouant de la mémoire pour ce qui devrait être une fonction de recherche
JaredPar

15
La comparaison avec ToLower () donnera des résultats différents à partir d'un IndexOf insensible à la casse lorsque deux lettres différentes ont la même lettre minuscule. Par exemple, appeler ToLower () sur U + 0398 "Lettre majuscule grecque Theta" ou U + 03F4 "Symbole lettre grecque Capital Theta" donne U + 03B8, "Lettre minuscule grecque Theta", mais les lettres majuscules sont considérées comme différentes. Les deux solutions considèrent les lettres minuscules avec la même majuscule différente, telles que U + 0073 "Latin Small Letter S" et U + 017F "Latin Small Letter Long S", de sorte que la solution IndexOf semble plus cohérente.
Quartermeister

3
@Quartermeister - et BTW, je crois que .NET 2 et .NET4 se comportent différemment à ce sujet car .NET 4 utilise toujours NORM_LINGUISTIC_CASING alors que .NET 2 ne l'a pas fait (ce drapeau est apparu avec Windows Vista).
Simon Mourier

10
Pourquoi n'avez-vous pas écrit "ddddfg" .IndexOf ("Df", StringComparison.OrdinalIgnoreCase)?
Chen

2713

Vous pouvez utiliser la méthode String.IndexOf et passer StringComparison.OrdinalIgnoreCasecomme type de recherche à utiliser:

string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;

Encore mieux est de définir une nouvelle méthode d'extension pour la chaîne:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source?.IndexOf(toCheck, comp) >= 0;
    }
}

Notez que la propagation nulle ?. est disponible depuis C # 6.0 (VS 2015), pour les anciennes versions, utilisez

if (source == null) return false;
return source.IndexOf(toCheck, comp) >= 0;

USAGE:

string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);

3
Grande méthode d'extension de chaîne! J'ai édité le mien pour vérifier que la chaîne source n'est pas nulle pour éviter toute erreur de référence d'objet lors de l'exécution de .IndexOf ().
Richard Pursehouse

8
Cela donne la même réponse paragraph.ToLower(culture).Contains(word.ToLower(culture))qu'avec CultureInfo.InvariantCultureet cela ne résout aucun problème de localisation. Pourquoi trop compliquer les choses? stackoverflow.com/a/15464440/284795
Colonel Panic

60
@ColonelPanic la ToLowerversion comprend 2 allocations qui ne sont pas nécessaires dans une opération de comparaison / recherche. Pourquoi allouer inutilement dans un scénario qui n'en a pas besoin?
JaredPar

4
@Seabiscuit qui ne fonctionnera pas parce stringque IEnumerable<char>vous ne pouvez pas l'utiliser pour trouver des sous
JaredPar

6
Un mot d'avertissement: La valeur par défaut pour string.IndexOf(string)est d'utiliser la culture actuelle, tandis que la valeur par défaut pour string.Contains(string)est d'utiliser le comparateur ordinal. Comme nous le savons, la première peut être modifiée en choisissant une surcharge plus longue, tandis que la seconde ne peut pas être modifiée. Une conséquence de cette incohérence est l'exemple de code suivant:Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string self = "Waldstrasse"; string value = "straße"; Console.WriteLine(self.Contains(value));/* False */ Console.WriteLine(self.IndexOf(value) >= 0);/* True */
Jeppe Stig Nielsen

231

Vous pouvez utiliser IndexOf()comme ceci:

string title = "STRING";

if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
{
    // The string exists in the original
}

Puisque 0 (zéro) peut être un index, vous vérifiez contre -1.

MSDN

Position d'index de base zéro de la valeur si cette chaîne est trouvée, ou -1 si elle ne l'est pas. Si la valeur est String.Empty, la valeur de retour est 0.


148

Solution alternative utilisant Regex:

bool contains = Regex.IsMatch("StRiNG to search", Regex.Escape("string"), RegexOptions.IgnoreCase);

6
Bonne idée, nous avons également beaucoup de combinaisons au niveau du bit dans RegexOptions comme RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant;pour n'importe qui si cela peut aider.
Saravanan

7
Je dois dire que je préfère cette méthode bien que j'utilise IsMatch pour la propreté.
wonea

31
Pire encore, puisque la chaîne de recherche est interprétée comme une expression régulière, un certain nombre de caractères de ponctuation entraîneront des résultats incorrects (ou déclencheront une exception en raison d'une expression non valide). Essayez "."dans "This is a sample string that doesn't contain the search string". Ou essayez de chercher "(invalid", d'ailleurs.
cHao

17
@cHao: Dans ce cas, Regex.Escapepourrait aider. Regex semble toujours inutile lorsque IndexOf/ extension Containsest simple (et sans doute plus clair).
Dan Mangiarelli

6
Notez que je n'impliquais pas que cette solution Regex était la meilleure solution. J'étais simplement en train d'ajouter à la liste des réponses à la question d'origine "Y a-t-il un moyen de rendre le retour suivant vrai?".
Jed

79

Vous pouvez toujours monter ou descendre les cordes en premier.

string title = "string":
title.ToUpper().Contains("STRING")  // returns true

Oups, je viens de voir ce dernier morceau. Une comparaison insensible à la casse ferait *probablement de *même de toute façon, et si les performances ne sont pas un problème, je ne vois pas de problème avec la création de copies majuscules et la comparaison. J'aurais juré avoir vu une fois une comparaison insensible à la casse ...


122
Rechercher "Turkey test" :)
Jon Skeet

7
Dans certains paramètres régionaux français, les lettres majuscules n'ont pas les signes diacritiques, donc ToUpper () peut ne pas être meilleur que ToLower (). Je dirais d'utiliser les bons outils s'ils sont disponibles - comparer insensible à la casse.
Blair Conrad le

5
N'utilisez pas ToUpper ou ToLower, et faites ce que Jon Skeet a dit
Peter Gfader

14
Je viens de revoir cela après deux ans et un nouveau downvote ... de toute façon, je suis d'accord qu'il existe de meilleures façons de comparer les chaînes. Cependant, tous les programmes ne seront pas localisés (la plupart ne le seront pas) et beaucoup sont des applications internes ou jetables. Étant donné que je ne peux guère m'attendre à ce que les conseils soient crédités pour les applications jetables ... Je passe à autre chose: D
Ed S.

8
La recherche de "Turquie test" est-elle identique à la recherche de "TURKEY TEST"?
JackAce

55

.NET Core 2.0+ uniquement (à partir de maintenant)

.NET Core a eu une paire de méthodes pour gérer cela depuis la version 2.0:

  • String.Contains (Char, StringComparison )
  • String.Contains (String, StringComparison )

Exemple:

"Test".Contains("test", System.StringComparison.CurrentCultureIgnoreCase);

Avec le temps, ils feront probablement leur chemin dans la norme .NET et, à partir de là, dans toutes les autres implémentations de la bibliothèque de classes de base.


1
Désormais également disponible dans .NET Standard 2.1
Paweł Bulwan

52

Un problème avec la réponse est qu'elle lèvera une exception si une chaîne est nulle. Vous pouvez ajouter cela comme un chèque afin qu'il ne:

public static bool Contains(this string source, string toCheck, StringComparison comp)
{
    if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
        return true;

    return source.IndexOf(toCheck, comp) >= 0;
} 

8
Si toCheck est la chaîne vide, il doit renvoyer true conformément à la documentation Contains: "true si le paramètre value se produit dans cette chaîne, ou si value est la chaîne vide (" "); sinon, false."
amurra

3
Sur la base du commentaire d'Amurra ci-dessus, le code suggéré n'a-t-il pas besoin d'être corrigé? Et cela ne devrait-il pas être ajouté à la réponse acceptée, afin que la meilleure réponse soit la première?
David White

13
Maintenant, cela retournera vrai si la source est une chaîne vide ou null, peu importe ce qu'est toCheck. Cela ne peut pas être correct. IndexOf renvoie également true si toCheck est une chaîne vide et que la source n'est pas nulle. Ce qui est nécessaire ici est une vérification de null. Je suggère si (source == null || value == null) return false;
Colin

2
La source ne peut pas être nulle
Lucas

1
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck);
Kyle Delaney

35

La classe StringExtension est la voie à suivre, j'ai combiné quelques-uns des articles ci-dessus pour donner un exemple de code complet:

public static class StringExtensions
{
    /// <summary>
    /// Allows case insensitive checks
    /// </summary>
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
}

pourquoi autorisez-vous une AUTRE couche d'abstraction StringComparison?
l --''''''----------------- '' '' '' '' '' ''

35

C'est propre et simple.

Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)

31
Cela correspondra à un modèle, cependant. Dans votre exemple, si fileNamestra des caractères spéciaux regex (par exemple *, +, ., etc.) , alors vous serez dans toute une surprise. La seule façon de faire fonctionner cette solution comme une Containsfonction appropriée est de s'échapper fileNamestren faisant Regex.Escape(fileNamestr).
XåpplI'-I0llwlg'I -

en outre, l'analyse et la mise en correspondance d'une expression
régulière nécessite

29

OrdinalIgnoreCase, CurrentCultureIgnoreCase ou InvariantCultureIgnoreCase?

Comme cela est manquant, voici quelques recommandations sur le moment de l'utiliser:

Dos

  • Utilisation StringComparison.OrdinalIgnoreCase pour les comparaisons votre valeur par défaut pour la correspondance de chaînes indépendante de la culture.
  • Utilisez des StringComparison.OrdinalIgnoreCasecomparaisons pour une vitesse accrue.
  • Utilisez StringComparison.CurrentCulture-baseddes opérations de chaîne lors de l'affichage de la sortie à l'utilisateur.
  • Basculez l'utilisation actuelle des opérations de chaîne basées sur la culture invariante pour utiliser le non-linguistique StringComparison.Ordinalou StringComparison.OrdinalIgnoreCaselorsque la comparaison est
    linguistiquement non pertinente (symbolique, par exemple).
  • Utilisez ToUpperInvariantplutôt que ToLowerInvariantlors de la normalisation des chaînes pour la comparaison.

À ne pas faire

  • Utilisez des surcharges pour les opérations de chaîne qui ne spécifient pas explicitement ou implicitement le mécanisme de comparaison de chaînes.
  • Utilisez StringComparison.InvariantCulturedes
    opérations de chaîne basées sur la plupart des cas; l'une des rares exceptions serait la
    persistance de données linguistiquement significatives mais culturellement agnostiques.

Sur la base de ces règles, vous devez utiliser:

string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
    // The string exists in the original
}

tandis que [YourDecision] dépend des recommandations ci-dessus.

lien de la source: http://msdn.microsoft.com/en-us/library/ms973919.aspx


Et si vous savez que vous aurez toujours une chaîne en anglais. lequel utiliser?
BKSpurgeon

1
@BKSpurgeon J'utiliserais OrdinalIgnoreCase, si le cas n'a pas d'importance
Fabian Bigler

20

Ce sont les solutions les plus simples.

  1. Par indice de

    string title = "STRING";
    
    if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
    {
        // contains 
    }
  2. En changeant de cas

    string title = "STRING";
    
    bool contains = title.ToLower().Contains("string")
  3. Par Regex

    Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);

11

Je sais que ce n'est pas le C #, mais dans le framework (VB.NET) il y a déjà une telle fonction

Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")

Variante C #:

string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");

11

La InStrméthode de l'assembly VisualBasic est la meilleure si vous avez un problème d'internationalisation (ou si vous pouvez la réimplémenter). En y regardant, dotNeetPeek montre que non seulement il tient compte des majuscules et des minuscules, mais aussi du type kana et des caractères pleine vs demi-largeur (surtout pertinent pour les langues asiatiques, bien qu'il existe aussi des versions pleine largeur de l'alphabet romain ). Je saute quelques détails, mais consultez la méthode privée InternalInStrText:

private static int InternalInStrText(int lStartPos, string sSrc, string sFind)
{
  int num = sSrc == null ? 0 : sSrc.Length;
  if (lStartPos > num || num == 0)
    return -1;
  if (sFind == null || sFind.Length == 0)
    return lStartPos;
  else
    return Utils.GetCultureInfo().CompareInfo.IndexOf(sSrc, sFind, lStartPos, CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth);
}


8

Utilisez ceci:

string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);

26
Le questionneur ne cherche Containspas Compare.
DuckMaestro

@DuckMaestro, la réponse acceptée est mise Containsen œuvre avec IndexOf. Cette approche est donc tout aussi utile! L'exemple de code C # sur cette page utilise string.Compare (). C'est le choix de l'équipe SharePoint!
vulcan raven

6

C'est assez similaire à un autre exemple ici, mais j'ai décidé de simplifier enum en bool, primaire car d'autres alternatives ne sont normalement pas nécessaires. Voici mon exemple:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, bool bCaseInsensitive )
    {
        return source.IndexOf(toCheck, bCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0;
    }
}

Et l'utilisation est quelque chose comme:

if( "main String substring".Contains("SUBSTRING", true) )
....

6

L'utilisation d'un RegEx est un moyen simple de le faire:

Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);

4
Votre réponse est exactement la même que celle de guptat59 mais, comme cela a été souligné dans sa réponse, cela correspondra à une expression régulière, donc si la chaîne que vous testez contient des caractères regex spéciaux, elle ne donnera pas le résultat souhaité.
Casey

2
Ceci est une copie directe de cette réponse et souffre des mêmes problèmes que ceux mentionnés dans cette réponse
Liam

D'accord. Étudier les expressions régulières
Jared

5

Juste pour construire sur la réponse ici, vous pouvez créer une méthode d'extension de chaîne pour la rendre un peu plus conviviale:

    public static bool ContainsIgnoreCase(this string paragraph, string word)
    {
        return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
    }

1
En supposant que votre paragraphe et votre mot seront toujours en-US
Boris Callens

3
Pour éviter les problèmes de forçage de la culture aux États-Unis, utilisez return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;plutôt.
AndrewWhalan

3

si vous voulez vérifier si votre chaîne passée est dans la chaîne, il existe une méthode simple pour cela.

string yourStringForCheck= "abc";
string stringInWhichWeCheck= "Test abc abc";

bool isContained = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1;

Cette valeur booléenne sera renvoyée si la chaîne est contenue ou non



2
if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;}

2

Vous pouvez utiliser la string.indexof ()fonction. Ce sera insensible à la casse


2

L'astuce ici est de rechercher la chaîne, en ignorant la casse, mais de la garder exactement la même (avec le même cas).

 var s="Factory Reset";
 var txt="reset";
 int first = s.IndexOf(txt, StringComparison.InvariantCultureIgnoreCase) + txt.Length;
 var subString = s.Substring(first - txt.Length, txt.Length);

La sortie est "Reset"


-1
public static class StringExtension
{
    #region Public Methods

    public static bool ExContains(this string fullText, string value)
    {
        return ExIndexOf(fullText, value) > -1;
    }

    public static bool ExEquals(this string text, string textToCompare)
    {
        return text.Equals(textToCompare, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExHasAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index]) == false) return false;
        return true;
    }

    public static bool ExHasEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return true;
        return false;
    }

    public static bool ExHasNoEquals(this string text, params string[] textArgs)
    {
        return ExHasEquals(text, textArgs) == false;
    }

    public static bool ExHasNotAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return false;
        return true;
    }

    /// <summary>
    /// Reports the zero-based index of the first occurrence of the specified string
    /// in the current System.String object using StringComparison.InvariantCultureIgnoreCase.
    /// A parameter specifies the type of search to use for the specified string.
    /// </summary>
    /// <param name="fullText">
    /// The string to search inside.
    /// </param>
    /// <param name="value">
    /// The string to seek.
    /// </param>
    /// <returns>
    /// The index position of the value parameter if that string is found, or -1 if it
    /// is not. If value is System.String.Empty, the return value is 0.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// fullText or value is null.
    /// </exception>
    public static int ExIndexOf(this string fullText, string value)
    {
        return fullText.IndexOf(value, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExNotEquals(this string text, string textToCompare)
    {
        return ExEquals(text, textToCompare) == false;
    }

    #endregion Public Methods
}

-4

Un moyen simple pour les débutants:

title.ToLower().Contains("string");//of course "string" is lowercase.

Downvote pour être simplement incorrect. Et si title = StRiNg? StRiNg! = String et StRiNg! = STRING
berniefitz

J'avais tort. Modifiez la réponse comme suit, trop simple simple: <br/> title.ToLower (). Contient ("string") // bien sûr "string" est en minuscules
O Thạnh Ldt
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.