Come verificare se una stringa contiene una qualsiasi di alcune stringhe


97

Voglio controllare se una stringa s, contiene "a" o "b" o "c", in C #. Sto cercando una soluzione migliore rispetto all'utilizzo

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

1
Per casi complessi, cerca la triestruttura dei dati.
Miserabile variabile

Risposte:


44

Se stai cercando caratteri singoli, puoi usare String.IndexOfAny().

Se vuoi stringhe arbitrarie, non sono a conoscenza di un metodo .NET per ottenerlo "direttamente", sebbene un'espressione regolare funzionerebbe.


94

Bene, c'è sempre questo:

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

    return false;
}

Utilizzo:

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

||Tuttavia, nulla potrà eguagliare le prestazioni della tua catena di confronti.


12
Aggiunta di una nuova sintassi breve a questa bella soluzione public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Soluzione semplice e ovvia. Ma esiste un'implementazione pronta per l'uso che non richieda più iterazioni tramite una stringa di pagliaio? Posso implementarlo da solo, iterando attraverso i caratteri della stringa del pagliaio e confrontando i primi caratteri degli aghi in sequenza in una volta sola, ma non posso credere che una soluzione così banale non sia ancora implementata in una nota libreria NuGet.
RollerKostr

@RollerKostr non è (ancora) integrato in C #, quindi perché aggiungere ulteriori dipendenze nel progetto per una soluzione così semplice?
jmdon

70

Ecco una soluzione LINQ che è praticamente la stessa ma più scalabile:

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

3
Questo è scalabile nel senso che è facile aggiungere personaggi, non nel senso della performance ... :)
Guffa

2
Ah sì, certo. Forse "più estensibile" sarebbe stata una scelta migliore di parole.
Jeff Mercado

La performance non sarà terribile. Meglio di una regexp interpretata, comunque.
Steven Sudit

Ottima risposta solo per completezza puoi prima suddividere la stringa in arrivo in un array, ad esempio: var splitStringArray = someString.Split (''); Quindi puoi fare qualcosa come: if (someStringArray.Any (s => otherString.Contains (s))) {// do something} Spero che aiuti qualcuno per chiarezza.
Tahir Khalid

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

21

Puoi provare con l'espressione regolare

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

1
+1, anche se dal momento che sta cercando caratteri singoli, una soluzione linq o indexOfAny potrebbe essere più efficiente.
Joel Coehoorn

+1 per l'espressione regolare. questo è quello che avrei voluto, se non ci fosse IndexOfAny
Stavros

1
Le espressioni regolari sono eccessive per questo.
Steven Sudit

3
Cosa fa dire alle persone che le regex sono eccessive per questo? Se la regex viene compilata una volta e utilizzata più volte, e hai stringhe con solo c in esse oc vicino all'inizio e a, b vicino alla fine, la regex sarebbe molto più efficiente.
bruceboughton

Non ha funzionato per caratteri speciali come -, '"
.`

14

Se hai bisogno di ContainsAny con uno specifico StringComparison(ad esempio per ignorare le maiuscole / minuscole), puoi utilizzare questo metodo String Extentions.

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

Utilizzo con 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.

2
Solo una nota per migliorare questa risposta. Puoi scriverlo ancora più ellegante con la parola chiave params: ContainsAny (questa stringa di input, StringComparison compareType, params string [] containsKeywords) e utilizzare come input.ContainsAny (sottostringhe, StringComparison.CurrentCultureIgnoreCase, "string", "many substrings" ... ecc)
Roma Borodov

7

Questa è una "soluzione migliore" e abbastanza semplice

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

4

Poiché una stringa è una raccolta di caratteri, puoi utilizzare i metodi di estensione LINQ su di essi:

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

Questo eseguirà la scansione della stringa una volta e si fermerà alla prima occorrenza, invece di scansionare la stringa una volta per ogni carattere finché non viene trovata una corrispondenza.

Questo può essere utilizzato anche per qualsiasi espressione che ti piace, ad esempio controllando un intervallo di caratteri:

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

Concordato. Questo risolve il problema di più scansioni quando le prime condizioni non corrispondono. Chissà qual è il sovraccarico della lambda? Non dovrebbe essere molto una volta però.
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));
}

Anyper qualsiasi, Allper ogni


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
I metodi HasWantedCharacters accettano due o tre stringhe. La prima stringa che vogliamo controllare per determinati caratteri. La seconda stringa, tutti i caratteri che cercheremo nella prima. Il metodo sovraccarico fornisce l'output al chiamante (cioè Main) come terza stringa. Un'istruzione foreach annidata passa attraverso ogni carattere nell'origine e lo confronta, uno per uno; con quei personaggi che stiamo cercando. Se uno dei caratteri viene trovato, restituisce vero. Il metodo sovraccarico restituisce una stringa di caratteri trovati corrispondenti a quelli controllati, ma non restituirà finché non saranno tutti esauriti. Utile?
Nate Wilkins,

1
Sentiti libero di avviare un progetto console C # e copiare il codice all'interno della classe del programma: assicurati di sostituire il metodo principale. Armeggia con le due stringhe (goodUserName e badUserName) e potresti vedere cosa fanno i metodi e come funzionano. Gli esempi sono più lunghi in modo da fornire una soluzione praticabile che può essere modificata senza delimitatori come le virgole. Le sequenze di escape sono solo un modo per rappresentare le virgolette singole e la barra rovesciata se è necessario verificarle.
Nate Wilkins,


0

Se stai cercando stringhe arbitrarie e non solo caratteri, puoi utilizzare un overload di IndexOfAny che accetta argomenti di stringa dal nuovo progetto NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.