[C#] "Insensible à la casse" Contient (chaîne) "



Answers

Vous pouvez utiliser la méthode String.IndexOf et transmettre StringComparison.OrdinalIgnoreCase comme type de recherche à utiliser:

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

Mieux vaut 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 cette propagation nulle ?. est disponible depuis C # 6.0 (VS 2015), pour les versions plus anciennes

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

USAGE:

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

Y at-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 MAJORE tous les deux, mais c'est idiot.

METTRE À JOUR
L'ineptie que je mentionne est les problèmes d' i18n qui viennent avec le haut et le bas du boîtier.

METTRE À JOUR
Cette question est ancienne et depuis je me suis rendu compte que je demandais une réponse simple pour un sujet vraiment vaste et difficile si vous voulez l'étudier complètement.
Dans la plupart des cas, dans des bases de code anglaises monolingues, this réponse suffira. Je me doute parce que la plupart des gens qui viennent ici tombent dans cette catégorie c'est la réponse la plus populaire.
This réponse soulève cependant le problème inhérent que nous ne pouvons pas comparer les cas de texte insensible jusqu'à ce que nous sachions que les deux textes sont la même culture et nous savons quelle est cette culture. C'est peut-être une réponse moins populaire, mais je pense que c'est plus correct et c'est pourquoi je l'ai marqué comme tel.




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




La méthode InStr de l'assembly VisualBasic est la meilleure si vous avez un problème d'internationalisation (ou vous pouvez le réimplémenter). En y regardant, dotNeetPeek montre que non seulement il prend en compte les majuscules et minuscules, mais aussi les caractères de type kana et les caractères pleins et demi-largeurs (surtout pour les langues asiatiques, bien qu'il existe aussi des versions pleine largeur de l'alphabet romain ). Je suis en train de sauter certains détails, mais jetez un œil à 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);
}



En fin de compte, une opération générique "contient" revient à une fonction comme celle-ci,

/// <summary>
/// Determines whether the source contains the sequence.
/// </summary>
/// <typeparam name="T">The type of the items in the sequences.</typeparam>
/// <param name="sourceEnumerator">The source enumerator.</param>
/// <param name="sequenceEnumerator">The sequence enumerator.</param>
/// <param name="equalityComparer">An equality comparer.</param>
/// <remarks>
/// An empty sequence will return <c>true</c>.
/// The sequence must support <see cref="IEnumerator.Reset"/>
/// if it does not begin the source.
/// </remarks>
/// <returns>
/// <c>true</c> if the source contains the sequence;
/// otherwise <c>false</c>.
/// </returns>
public static bool Contains<T>(
    IEnumerator<T> sourceEnumerator,
    IEnumerator<T> sequenceEnumerator,
    IEqualityComparer<T> equalityComparer)
{
    if (equalityComparer == null)
    {
        equalityComparer = EqualityComparer<T>.Default;
    }

    while (sequenceEnumerator.MoveNext())
    {
        if (sourceEnumerator.MoveNext())
        {
            if (!equalityComparer.Equals(
                sourceEnumerator.Current,
                sequenceEnumerator.Current))
            {
                sequenceEnumerator.Reset();
            }
        }
        else
        {
            return false;
        }
    }

    return true;
}

ceci peut être trivialement enveloppé dans une version d'extension acceptant IEnumerable comme ceci,

public static bool Contains<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> equalityComparer = null)
{
    if (sequence == null)
    {
        throw new ArgumentNullException("sequence");
    }

    using(var sequenceEnumerator = sequence.GetEnumerator())
    using(var sourceEnumerator = source.GetEnumerator())
    {
        return Contains(
            sourceEnumerator,
            sequenceEnumerator,
            equalityComparer);
    }
}

Maintenant, cela fonctionnera pour la comparaison ordinale de toutes les séquences, y compris les chaînes, puisque la string implémente IEnumerable<char> ,

// The optional parameter ensures the generic overload is invoked
// not the string.Contains() implementation.
"testable".Contains("est", EqualityComparer<char>.Default)

Cependant, comme nous le savons, les chaînes ne sont pas génériques, elles sont spécialisées. Il y a deux facteurs clés en jeu.

  1. Le problème de "casing" qui a lui-même différents cas de limites dépendant de la langue.
  2. La question plutôt complexe de la façon dont un ensemble d'éléments textuels (lettres / chiffres / symboles etc.) est représenté par des points de code Unicode et quelles séquences valides de caractères peuvent représenter une chaîne donnée, les détails sont développés dans these answers .

L'effet net est le même. Les chaînes que vous pourriez affirmer sont linguistiquement égales peuvent être valablement représentées par différentes combinaisons de caractères. Quoi de plus, les règles de validité changent entre les cultures.

Tout ceci conduit à une implémentation "Contains" basée sur une chaîne spécialisée comme celle-ci.

using System.Globalization;

public static bool Contains(
         this string source,
         string value,
         CultureInfo culture = null,
         CompareOptions options = CompareOptions.None)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }

    var compareInfo = culture == null ? 
            CultureInfo.CurrentCulture.CompareInfo :
            culture.CompareInfo;

    var sourceEnumerator = StringInfo.GetTextElementEnumerator(source);
    var sequenceEnumerator = StringInfo.GetTextElementEnumerator(value);

    while (sequenceEnumerator.MoveNext())
    {
        if (sourceEnumerator.MoveNext())
        {
            if (!(compareInfo.Compare(
                    sourceEnumerator.Current,
                    sequenceEnumerator.Current,
                    options) == 0))
            {
                sequenceEnumerator.Reset();
            }
        }
        else
        {
            return false;
        }
    }

    return true;
}

Cette fonction peut être utilisée pour effectuer une "culture" spécifique à la casse, qui va fonctionner, quelle que soit la normalisation des chaînes. par exemple

"testable".Contains("EST", StringComparer.CurrentCultureIgnoreCase)



Autre solution utilisant Regex:

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

Remarquer

Comme @cHao l'a souligné dans son commentaire, il y a des scénarios qui provoqueront des résultats incorrects. Assurez-vous de savoir ce que vous faites avant d'implanter cette solution au hasard.




Juste comme ça:

string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
    Console.WriteLine("yes");
}



C'est propre et simple.

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



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
}



Ceci est assez similaire à un autre exemple ici, mais j'ai décidé de simplifier enum à bool, primaire parce que 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) )
....



Un problème avec la réponse est qu'il lancera une exception si une chaîne est nulle. Vous pouvez ajouter cela comme une vérification, donc ce ne sera pas:

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;
} 



Manière simple pour le débutant:

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





Links