Comment vérifier si une chaîne contient l'une de certaines chaînes


98

Je veux vérifier si une chaîne s, contient "a" ou "b" ou "c", en C #. Je recherche une meilleure solution que d'utiliser

if (s.contains("a")||s.contains("b")||s.contains("c"))

1
Pour les cas complexes, recherchez triela structure des données.
Variable misérable

Réponses:


44

Si vous recherchez des caractères uniques, vous pouvez utiliser String.IndexOfAny().

Si vous voulez des chaînes arbitraires, je ne connais pas de méthode .NET pour y parvenir "directement", bien qu'une expression régulière fonctionnerait.


94

Eh bien, il y a toujours ceci:

public static bool ContainsAny(this string haystack, params string[] needles)
{
    foreach (string needle in needles)
    {
        if (haystack.Contains(needle))
            return true;
    }

    return false;
}

Usage:

bool anyLuck = s.ContainsAny("a", "b", "c");

||Cependant, rien ne pourra égaler les performances de votre chaîne de comparaisons.


12
Ajout d'une nouvelle syntaxe courte à cette belle solution public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Solution simple et évidente. Mais y a-t-il une bonne implémentation prête à l'emploi qui ne nécessite pas plusieurs itérations via une chaîne de haystack? Je peux l'implémenter moi-même, en itérant à travers des caractères de chaîne de botte de foin et en comparant les premiers caractères des aiguilles séquentiellement en une seule fois, mais je ne peux pas croire qu'une telle solution triviale ne soit pas encore implémentée dans une bibliothèque NuGet bien connue.
RollerKostr

@RollerKostr Ce n'est pas (encore) intégré à C #, alors pourquoi ajouter des dépendances supplémentaires dans votre projet pour une solution aussi simple?
jmdon

70

Voici une solution LINQ qui est pratiquement la même mais plus évolutive:

new[] { "a", "b", "c" }.Any(c => s.Contains(c))

3
C'est évolutif dans le sens où il est facile d'ajouter des personnages, pas dans le sens de la performance ... :)
Guffa

2
Ah oui, bien sûr. Peut-être que «plus extensible» aurait été un meilleur choix de mots.
Jeff Mercado

La performance ne sera pas terrible. Mieux qu'une expression rationnelle interprétée, de toute façon.
Steven Sudit

Réponse géniale juste pour être complète, vous pouvez d'abord diviser votre chaîne entrante en un tableau, par exemple: var splitStringArray = someString.Split (''); Ensuite, vous pouvez faire quelque chose comme: if (someStringArray.Any (s => otherString.Contains (s))) {// faire quelque chose} J'espère que cela aide quelqu'un pour plus de clarté.
Tahir Khalid

45
var values = new [] {"abc", "def", "ghj"};
var str = "abcedasdkljre";
values.Any(str.Contains);

21

Vous pouvez essayer avec une expression régulière

string s;
Regex r = new Regex ("a|b|c");
bool containsAny = r.IsMatch (s);

1
+1, mais comme il recherche des caractères uniques, une solution linq ou indexOfAny pourrait être plus efficace.
Joel Coehoorn

+1 pour l'expression régulière. c'est ce que j'aurais fait, s'il n'y avait pas IndexOfAny
Stavros

1
Les expressions régulières sont excessives pour cela.
Steven Sudit

3
Qu'est-ce qui fait que les gens disent que les expressions régulières sont excessives pour cela? Si l'expression régulière est compilée une fois et utilisée plusieurs fois, et que vous avez des chaînes avec seulement c ou c près du début et a, b près de la fin, l'expression régulière serait beaucoup plus efficace.
bruceboughton

Cela

15

Si vous avez besoin de ContainsAny avec un spécifique StringComparison(par exemple pour ignorer la casse), vous pouvez utiliser cette méthode d'extensions de chaîne.

public static class StringExtensions
{
    public static bool ContainsAny(this string input, IEnumerable<string> containsKeywords, StringComparison comparisonType)
    {
        return containsKeywords.Any(keyword => input.IndexOf(keyword, comparisonType) >= 0);
    }
}

Utilisation avec StringComparison.CurrentCultureIgnoreCase:

var input = "My STRING contains Many Substrings";
var substrings = new[] {"string", "many substrings", "not containing this string" };
input.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// The statement above returns true.

xyz”.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// This statement returns false.

3
Juste une note pour améliorer cette réponse. Vous pouvez l'écrire encore plus ellegant avec le mot-clé params: ContainsAny (cette entrée de chaîne, StringComparison comparaisonType, params string [] containsKeywords) et utiliser comme input.ContainsAny (substrings, StringComparison.CurrentCultureIgnoreCase, "string", "many substrings" ... etc)
Roma Borodov

7

C'est une "meilleure solution" et assez simple

if(new string[] { "A", "B", ... }.Any(s=>myString.Contains(s)))

4

Comme une chaîne est une collection de caractères, vous pouvez utiliser des méthodes d'extension LINQ sur eux:

if (s.Any(c => c == 'a' || c == 'b' || c == 'c')) ...

Cela analysera la chaîne une fois et s'arrêtera à la première occurrence, au lieu de scanner la chaîne une fois pour chaque caractère jusqu'à ce qu'une correspondance soit trouvée.

Cela peut également être utilisé pour toute expression que vous aimez, par exemple en vérifiant une plage de caractères:

if (s.Any(c => c >= 'a' && c <= 'c')) ...

D'accord. Cela résout le problème des analyses multiples lorsque les premières conditions ne correspondent pas. Vous vous demandez ce que sont les frais généraux du lambda? Cela ne devrait pas être beaucoup une fois.
bruceboughton

3
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
    return needles.Any(haystack.Contains);
}

3
List<string> includedWords = new List<string>() { "a", "b", "c" };
bool string_contains_words = includedWords.Exists(o => s.Contains(o));

2
// Nice method's name, @Dan Tao

public static bool ContainsAny(this string value, params string[] params)
{
    return params.Any(p => value.Compare(p) > 0);
    // or
    return params.Any(p => value.Contains(p));
}

Anypour tout, Allpour chaque


2
    static void Main(string[] args)
    {
        string illegalCharacters = "!@#$%^&*()\\/{}|<>,.~`?"; //We'll call these the bad guys
        string goodUserName = "John Wesson";                   //This is a good guy. We know it. We can see it!
                                                               //But what if we want the program to make sure?
        string badUserName = "*_Wesson*_John!?";                //We can see this has one of the bad guys. Underscores not restricted.

        Console.WriteLine("goodUserName " + goodUserName +
            (!HasWantedCharacters(goodUserName, illegalCharacters) ?
            " contains no illegal characters and is valid" :      //This line is the expected result
            " contains one or more illegal characters and is invalid"));
        string captured = "";
        Console.WriteLine("badUserName " + badUserName +
            (!HasWantedCharacters(badUserName, illegalCharacters, out captured) ?
            " contains no illegal characters and is valid" :
            //We can expect this line to print and show us the bad ones
            " is invalid and contains the following illegal characters: " + captured));  

    }

    //Takes a string to check for the presence of one or more of the wanted characters within a string
    //As soon as one of the wanted characters is encountered, return true
    //This is useful if a character is required, but NOT if a specific frequency is needed
    //ie. you wouldn't use this to validate an email address
    //but could use it to make sure a username is only alphanumeric
    static bool HasWantedCharacters(string source, string wantedCharacters)
    {
        foreach(char s in source) //One by one, loop through the characters in source
        {
            foreach(char c in wantedCharacters) //One by one, loop through the wanted characters
            {
                if (c == s)  //Is the current illegalChar here in the string?
                    return true;
            }
        }
        return false;
    }

    //Overloaded version of HasWantedCharacters
    //Checks to see if any one of the wantedCharacters is contained within the source string
    //string source ~ String to test
    //string wantedCharacters ~ string of characters to check for
    static bool HasWantedCharacters(string source, string wantedCharacters, out string capturedCharacters)
    {
        capturedCharacters = ""; //Haven't found any wanted characters yet

        foreach(char s in source)
        {
            foreach(char c in wantedCharacters) //Is the current illegalChar here in the string?
            {
                if(c == s)
                {
                    if(!capturedCharacters.Contains(c.ToString()))
                        capturedCharacters += c.ToString();  //Send these characters to whoever's asking
                }
            }
        }

        if (capturedCharacters.Length > 0)  
            return true;
        else
            return false;
    }

1
Les méthodes HasWantedCharacters acceptent deux ou trois chaînes. La première chaîne que nous voulons vérifier pour certains caractères. La deuxième chaîne, tous les caractères que nous rechercherons dans la première. La méthode surchargée fournit une sortie à l'appelant (c'est-à-dire Main) sous la forme d'une troisième chaîne. Une instruction foreach imbriquée parcourt chaque caractère de la source et le compare, un par un; avec ces personnages que nous recherchons. Si l'un des caractères est trouvé, il renvoie vrai. La méthode surchargée génère une chaîne de caractères trouvés correspondant à ceux vérifiés, mais ne retournera pas tant que tous ne seront pas sortis. Utile?
Nate Wilkins

1
N'hésitez pas à démarrer un projet de console C # et à copier le code à l'intérieur de la classe de programme - assurez-vous de remplacer la méthode main. Bricolez les deux chaînes (goodUserName et badUserName) et vous verrez peut-être ce que font les méthodes et comment elles fonctionnent. Les exemples sont plus longs afin de fournir une solution viable qui peut être modifiée sans délimiteurs comme des virgules. Les séquences d'échappement ne sont qu'un moyen de représenter le guillemet simple et la barre oblique inverse si vous avez besoin de les vérifier.
Nate Wilkins

1

Vous pouvez utiliser des expressions régulières

if(System.Text.RegularExpressions.IsMatch("a|b|c"))

Vous pouvez certainement, mais je ne vois pas pourquoi vous voudriez le faire alors que presque tout le reste est mieux.
Steven Sudit

0

Si vous recherchez des chaînes arbitraires, et pas seulement des caractères, vous pouvez utiliser une surcharge d'IndexOfAny qui prend les arguments de chaîne du nouveau projet NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
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.