So überprüfen Sie, ob ein String einen String enthält


97

Ich möchte überprüfen, ob ein String s in C # "a" oder "b" oder "c" enthält. Ich suche nach einer schöneren Lösung als mit

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

1
Für komplexe Fälle trieDatenstruktur nachschlagen .
Elende Variable

Antworten:


44

Wenn Sie nach einzelnen Zeichen suchen, können Sie verwenden String.IndexOfAny().

Wenn Sie beliebige Zeichenfolgen möchten, ist mir keine .NET-Methode bekannt, mit der dies "direkt" erreicht werden kann, obwohl ein regulärer Ausdruck funktionieren würde.


94

Nun, es gibt immer Folgendes:

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

    return false;
}

Verwendung:

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

Nichts wird jedoch mit der Leistung Ihrer ||Vergleichskette mithalten können.


12
Hinzufügen einer neuen kurzen Syntax zu dieser netten Lösung public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Einfache und offensichtliche Lösung. Aber gibt es eine gute gebrauchsfertige Implementierung, die nicht mehrere Iterationen durch Heuhaufen erfordert? Ich kann es selbst implementieren, indem ich Heuhaufen-Zeichenfolgen durchlaufe und die ersten Zeichen von Nadeln nacheinander auf einmal vergleiche, aber ich kann nicht glauben, dass eine solche triviale Lösung noch nicht in einer bekannten NuGet-Bibliothek implementiert ist.
RollerKostr

@RollerKostr Es ist (noch) nicht in C # integriert. Warum sollten Sie Ihrem Projekt zusätzliche Abhängigkeiten hinzufügen, um eine so einfache Lösung zu erhalten?
jmdon

70

Hier ist eine LINQ-Lösung, die praktisch identisch, aber skalierbarer ist:

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

3
Das ist skalierbar in dem Sinne, dass es einfach ist, Zeichen hinzuzufügen, nicht im Sinne von Leistung ... :)
Guffa

2
Ach ja natürlich. Vielleicht wäre "erweiterbarer" eine bessere Wortwahl gewesen.
Jeff Mercado

Die Leistung wird nicht schrecklich sein. Jedenfalls besser als ein interpretierter regulärer Ausdruck.
Steven Sudit

Nur der Vollständigkeit halber können Sie Ihre eingehende Zeichenfolge zunächst in ein Array aufteilen, z. B.: Var splitStringArray = someString.Split (''); Dann können Sie Folgendes tun: if (someStringArray.Any (s => otherString.Contains (s))) {// etwas tun} Hoffe, dass jemand zur Klarheit beiträgt.
Tahir Khalid

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

21

Sie können es mit regulären Ausdrücken versuchen

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

1
+1, da er nach einzelnen Zeichen sucht, ist eine linq-Lösung oder indexOfAny möglicherweise effizienter.
Joel Coehoorn

+1 für den regulären Ausdruck. Dafür hätte ich mich entschieden, wenn es nicht IndexOfAny
Stavros

1
Reguläre Ausdrücke sind dafür übertrieben.
Steven Sudit

3
Was lässt die Leute sagen, dass Regexes dafür übertrieben sind? Wenn der reguläre Ausdruck einmal kompiliert und mehrfach verwendet wird und Sie Zeichenfolgen mit nur c oder c am Anfang und a, b am Ende haben, ist der reguläre Ausdruck weitaus effizienter.
Bruceboughton

Es funktioniert nicht für Sonderzeichen wie -, '"
.`

14

Wenn Sie ContainsAny mit einer bestimmten StringComparisonMethode benötigen (z. B. um Groß- und Kleinschreibung zu ignorieren), können Sie diese String Extentions-Methode verwenden.

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

Verwendung mit 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
Nur eine Anmerkung, um diese Antwort zu verbessern. Sie könnten es mit dem Schlüsselwort params noch elleganter schreiben: ContainsAny (diese Zeichenfolgeneingabe, StringComparison compareType, params string [] enthält Schlüsselwörter) und wie input.ContainsAny (Teilzeichenfolgen, StringComparison.CurrentCultureIgnoreCase, "Zeichenfolge", "viele Teilzeichenfolgen" ... verwenden). etc)
Roma Borodov

7

Dies ist eine "schönere Lösung" und recht einfach

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

4

Da eine Zeichenfolge eine Sammlung von Zeichen ist, können Sie LINQ-Erweiterungsmethoden verwenden:

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

Dadurch wird die Zeichenfolge einmal gescannt und beim ersten Auftreten angehalten, anstatt die Zeichenfolge einmal für jedes Zeichen zu scannen, bis eine Übereinstimmung gefunden wird.

Dies kann auch für einen beliebigen Ausdruck verwendet werden, z. B. zum Überprüfen einer Reihe von Zeichen:

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

Einverstanden. Dies löst das Problem mehrerer Scans, wenn die ersten Bedingungen nicht übereinstimmen. Frage mich, was der Overhead des Lambda ist? Sollte aber nicht viel sein.
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));
}

Anyfür jeden, Allfür jeden


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
Die Methoden HasWantedCharacters akzeptieren zwei oder drei Zeichenfolgen. Die erste Zeichenfolge, die wir auf bestimmte Zeichen überprüfen möchten. Die zweite Zeichenfolge, alle Zeichen, nach denen wir in der ersten suchen werden. Die überladene Methode liefert eine Ausgabe an den Aufrufer (dh Main) als dritte Zeichenfolge. Eine verschachtelte foreach-Anweisung durchläuft jedes Zeichen in der Quelle und vergleicht es einzeln. mit diesen Zeichen suchen wir. Wenn eines der Zeichen gefunden wird, wird true zurückgegeben. Die überladene Methode gibt eine Zeichenfolge aus, die mit den überprüften Zeichen übereinstimmt, wird jedoch erst zurückgegeben, wenn alle gelöscht sind. Hilfreich?
Nate Wilkins

1
Starten Sie ein C # -Konsolenprojekt und kopieren Sie den Code in die Programmklasse. Ersetzen Sie unbedingt die Hauptmethode. Wenn Sie an den beiden Zeichenfolgen (goodUserName und badUserName) basteln, sehen Sie möglicherweise, was die Methoden tun und wie sie funktionieren. Die Beispiele sind länger, um eine funktionsfähige Lösung bereitzustellen, die ohne Trennzeichen wie Kommas geändert werden kann. Escape-Sequenzen sind nur eine Möglichkeit, das einfache Anführungszeichen und den Backslash darzustellen, wenn Sie nach ihnen suchen müssen.
Nate Wilkins


0

Wenn Sie nach beliebigen Zeichenfolgen und nicht nur nach Zeichen suchen, können Sie eine Überladung von IndexOfAny verwenden, die Zeichenfolgenargumente aus dem neuen Projekt NLib übernimmt :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.