Як перевірити, чи містить рядок який-небудь рядок


98

Я хочу перевірити, чи рядок s містить "a", "b" або "c" у C #. Я шукаю кращого рішення, ніж використання

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

1
Для складних випадків шукайте trieструктуру даних.
Мізерна змінна

Відповіді:


44

Якщо ви шукаєте окремих символів, ви можете використовувати String.IndexOfAny().

Якщо ви хочете довільні рядки, то я не знаю методу .NET для досягнення цього "безпосередньо", хоча регулярний вираз буде працювати.


94

Ну, завжди є таке:

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

    return false;
}

Використання:

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

||Однак ніщо не збігається з ефективністю вашого ланцюга порівнянь.


12
Додавання нового короткого синтаксису до цього приємного рішення public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1,

Просте і очевидне рішення. Але чи існує якась готова до використання реалізація, яка не потребує численних ітерацій через рядок копиці сіна? Я можу реалізувати це самостійно, перебираючи рядки символів копиці сіна і порівнюючи послідовно перші символи голок за один раз, але я не можу повірити, що таке тривіальне рішення ще не реалізоване в якійсь відомій бібліотеці NuGet.
RollerKostr

@RollerKostr Він ще не вбудований в C # (поки), то навіщо додавати додаткові залежності у свій проект для такого простого рішення?
jmdon

70

Ось рішення LINQ, яке є практично однаковим, але більш масштабованим:

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

3
Це масштабовано в тому сенсі, що легко додавати символи, а не у сенсі продуктивності ... :)
Guffa

2
Ах так, звичайно. Можливо, "більш розтяжним" був би кращий вибір слів.
Джефф Меркадо,

Виступ не буде жахливим. Так чи інакше, ніж інтерпретований регулярний вираз.
Steven Sudit

Чудова відповідь лише для повноти, ви можете спочатку розділити вхідний рядок на масив, наприклад: var splitStringArray = someString.Split (''); Тоді ви можете зробити щось на зразок: if (someStringArray.Any (s => otherString.Contains (s))) {// зробити щось} Сподіваюся, що допоможе комусь для ясності.
Тахір Халід


21

Можна спробувати з регулярними виразами

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

1
+1, хоча, оскільки він шукає одиничні символи, рішення linq або indexOfAny може бути більш ефективним.
Джоел Коухорн,

+1 для регулярного виразу. на це я б пішов, якби не було IndexOfAny
Ставрос

1
Регулярні вирази для цього непосильні.
Стівен Судіт,

3
Що змушує людей говорити, що регулярні вирази надмірні для цього? Якщо регулярний вираз компілюється один раз і використовується кілька разів, і у вас є рядки, в яких лише c або c біля початку та a, b біля кінця, регулярний вираз буде набагато ефективнішим.
bruceboughton,

Це не спрацювало для спеціальних символів, таких як -, '"
.`

15

Якщо вам потрібен ContainsAny з певним StringComparison(наприклад, щоб ігнорувати регістр), ви можете використовувати цей метод розширення рядків.

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

Використання з 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
Лише одна примітка, щоб покращити цю відповідь. Ви можете написати його ще більш вишукано за допомогою ключового слова params: ContainsAny (цей рядок введення, StringComparison порівнянняType, params рядок [] міститьKeywords) і використовувати як input.ContainsAny (підрядки, StringComparison.CurrentCultureIgnoreCase, "рядок", "багато підрядків" ... і т. д.)
Рома Бородов

7

Це "приємніше рішення" і досить просте

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

4

Оскільки рядок - це набір символів, ви можете використовувати для них методи розширення LINQ:

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

Це просканує рядок один раз і зупиниться при першій появі, замість того, щоб просканувати рядок один раз для кожного символу, поки не буде знайдено збіг.

Це також можна використовувати для будь-якого вподобаного виразу, наприклад, для перевірки діапазону символів:

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

Домовились. Це вирішує проблему багаторазового сканування, коли перші умови не збігаються. Цікаво, що це накладні витрати на лямбду? Хоча не повинно бути багато разів.
bruceboughton

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


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

Anyдля будь-якого, Allдля кожного


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
Методи HasWantedCharacters приймають два-три рядки. Перший рядок, який ми хочемо перевірити на наявність певних символів. Другий рядок, усі символи, які ми будемо шукати в першому. Перевантажений метод забезпечує вихід для абонента (тобто головного) у вигляді третього рядка. Вкладений оператор foreach проходить кожен символ у джерелі та порівнює його, по одному; з тими символами, які ми перевіряємо. Якщо один із символів знайдений, він повертає true. Перевантажений метод видає рядок знайдених символів, що відповідають тим, на які перевірено, але не повернеться, поки всі не закінчаться. Корисно?
Nate Wilkins

1
Не соромтеся починати проект консолі C # і копіювати код всередині класу програми - обов’язково замініть основний метод. Поводьтеся з двома рядками (goodUserName і badUserName), і ви можете побачити, що саме роблять методи і як вони працюють. Приклади довші, щоб надати дієве рішення, яке можна змінити без роздільників, таких як коми. Екранні послідовності - це лише один із способів представити одинарну лапку та зворотну косу риску, якщо вам потрібно перевірити їх наявність.
Nate Wilkins


0

Якщо ви шукаєте довільні рядки, а не лише символи, ви можете використовувати перевантаження IndexOfAny, яке бере аргументи рядка з нового проекту NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.