Bagaimana cara memeriksa apakah suatu String berisi salah satu dari beberapa string


98

Saya ingin memeriksa apakah String s, berisi "a" atau "b" atau "c", di C #. Saya mencari solusi yang lebih bagus daripada menggunakan

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

1
Untuk kasus yang kompleks, lihat triestruktur data.
Variabel Miserable

Jawaban:


44

Jika Anda mencari karakter tunggal, Anda dapat menggunakan String.IndexOfAny().

Jika Anda menginginkan string arbitrer, maka saya tidak mengetahui metode .NET untuk mencapai itu "secara langsung", meskipun ekspresi reguler akan berfungsi.


94

Nah, selalu ada ini:

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

    return false;
}

Pemakaian:

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

Namun, tidak ada yang akan menandingi kinerja rantai ||perbandingan Anda.


12
Menambahkan sintaks pendek baru ke solusi bagus ini public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Solusi sederhana dan jelas. Tetapi apakah ada implementasi siap pakai yang baik yang tidak memerlukan banyak iterasi melalui string tumpukan jerami? Saya dapat menerapkannya sendiri, mengulangi karakter string tumpukan jerami dan membandingkan karakter pertama jarum secara berurutan sekaligus, tetapi saya tidak percaya bahwa solusi sepele seperti itu belum diterapkan di beberapa pustaka NuGet yang terkenal.
RollerKostr

@RollerKostr Ini belum dibangun ke dalam C # (belum) jadi mengapa menambahkan ketergantungan tambahan dalam proyek Anda untuk solusi sederhana seperti itu?
jmdon

70

Berikut solusi LINQ yang hampir sama tetapi lebih skalabel:

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

3
Itu dapat diskalakan dalam arti mudah untuk menambahkan karakter, bukan dalam arti kinerja ... :)
Guffa

2
Ah ya tentu saja. Mungkin "lebih bisa diperluas" adalah pilihan kata yang lebih baik.
Jeff Mercado

Performanya tidak akan buruk. Lebih baik daripada regexp yang ditafsirkan.
Steven Sudit

Jawaban mengagumkan hanya untuk kelengkapan Anda dapat membagi string masuk Anda menjadi sebuah array terlebih dahulu misalnya: var splitStringArray = someString.Split (''); Kemudian Anda dapat melakukan sesuatu seperti: if (someStringArray.Any (s => otherString.Contains (s))) {// do something} Harapan yang membantu seseorang untuk kejelasan.
Tahir Khalid

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

21

Anda dapat mencoba dengan ekspresi reguler

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

1
+1, meskipun karena dia sedang mencari karakter tunggal, solusi linq atau indexOfAny mungkin lebih efisien.
Joel Coehoorn

1 untuk ekspresi reguler. itulah yang akan saya lakukan, jika tidak ada IndexOfAny
Stavros

1
Ekspresi reguler berlebihan untuk ini.
Steven Sudit

3
Apa yang membuat orang mengatakan regex berlebihan untuk ini? Jika regex dikompilasi sekali dan digunakan beberapa kali, dan Anda memiliki string dengan hanya c di dalamnya atau c di dekat awal dan a, b di dekat akhir, regex akan jauh lebih efisien.
bruceboughton

Ini tidak berfungsi untuk karakter khusus seperti -, '"
.`

15

Jika Anda membutuhkan ContainsAny dengan spesifik StringComparison(misalnya untuk mengabaikan kasus) maka Anda dapat menggunakan metode Ekstensi String ini.

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

Penggunaan dengan 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
Hanya satu catatan untuk meningkatkan jawaban ini. Anda dapat menuliskannya lebih ellegant dengan kata kunci params: ContainsAny (input string ini, StringComparisonType, params string [] containsKeywords) dan gunakan seperti input.ContainsAny (substring, StringComparison.CurrentCultureIgnoreCase, "string", "many substrings" ... dll)
Roma Borodov

7

Ini adalah "solusi yang lebih baik" dan cukup sederhana

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

4

Karena string adalah kumpulan karakter, Anda dapat menggunakan metode ekstensi LINQ padanya:

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

Ini akan memindai string sekali dan berhenti pada kejadian pertama, alih-alih memindai string satu kali untuk setiap karakter hingga ditemukan kecocokan.

Ini juga dapat digunakan untuk ekspresi apa pun yang Anda suka, misalnya memeriksa rentang karakter:

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

Sepakat. Ini memecahkan masalah beberapa pemindaian saat kondisi pertama tidak cocok. Ingin tahu apa overhead lambda itu? Seharusnya tidak banyak sekali.
bruceboughton

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

Anyuntuk setiap, Alluntuk setiap


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
Metode HasWantedCharacters menerima dua atau tiga string. String pertama yang ingin kami periksa untuk karakter tertentu. String kedua, semua karakter yang akan kita cari di string pertama. Metode kelebihan beban memberikan keluaran ke pemanggil (yaitu Utama) sebagai string ketiga. Pernyataan foreach bersarang melewati setiap karakter dalam sumber dan membandingkannya, satu per satu; dengan karakter yang kami periksa. Jika salah satu karakter ditemukan, itu mengembalikan true. Metode kelebihan beban mengeluarkan string karakter yang ditemukan cocok dengan yang diperiksa, tetapi tidak akan kembali sampai semuanya keluar. Bermanfaat?
Nate Wilkins

1
Jangan ragu untuk memulai proyek konsol C # dan menyalin kode di dalam kelas program-pastikan untuk mengganti metode utama. Bermain-main dengan dua string (goodUserName dan badUserName) dan Anda mungkin melihat apa yang dilakukan metode dan cara kerjanya. Contoh-contohnya lebih panjang untuk memberikan solusi yang bisa diterapkan yang dapat dimodifikasi tanpa pembatas seperti koma. Urutan melarikan diri hanyalah satu cara untuk merepresentasikan kutipan tunggal dan garis miring terbalik jika Anda perlu memeriksanya.
Nate Wilkins

1

Anda dapat menggunakan Ekspresi Reguler

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

Anda tentu bisa, tetapi saya tidak mengerti mengapa Anda ingin melakukannya ketika hampir semua hal lain lebih baik.
Steven Sudit

0

Jika Anda mencari string arbitrer, dan bukan hanya karakter, Anda dapat menggunakan overload IndexOfAny yang mengambil argumen string dari project baru NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.