Cách kiểm tra xem một Chuỗi có chứa bất kỳ chuỗi nào trong số một số chuỗi hay không


97

Tôi muốn kiểm tra xem một Chuỗi s, chứa "a" hoặc "b" hoặc "c", trong C #. Tôi đang tìm kiếm một giải pháp tốt hơn là sử dụng

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

1
Đối với các trường hợp phức tạp, tra cứu triecấu trúc dữ liệu.
Biến số khốn khổ

Câu trả lời:


44

Nếu bạn đang tìm kiếm các ký tự đơn, bạn có thể sử dụng String.IndexOfAny().

Nếu bạn muốn các chuỗi tùy ý, thì tôi không biết phương thức .NET để đạt được điều đó "trực tiếp", mặc dù một biểu thức chính quy sẽ hoạt động.


94

Chà, luôn có điều này:

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

    return false;
}

Sử dụng:

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

||Tuy nhiên, sẽ không có gì phù hợp với hiệu suất của chuỗi so sánh của bạn .


12
Thêm cú pháp ngắn mới vào giải pháp hay này public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Giải pháp đơn giản và rõ ràng. Nhưng có bất kỳ triển khai sẵn sàng sử dụng nào tốt mà không yêu cầu nhiều lần lặp lại thông qua chuỗi haystack không? Tôi có thể tự mình thực hiện nó, lặp qua các ký tự chuỗi haystack và so sánh các ký tự đầu tiên của kim một cách tuần tự trong một lần, nhưng tôi không thể tin rằng giải pháp tầm thường như vậy chưa được triển khai trong một số thư viện NuGet nổi tiếng.
RollerKostr

@RollerKostr Nó chưa được tích hợp sẵn trong C #, vậy tại sao phải thêm các phần phụ thuộc bổ sung vào dự án của bạn để có một giải pháp đơn giản như vậy?
jmdon

70

Đây là một giải pháp LINQ gần như giống nhau nhưng có khả năng mở rộng hơn:

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

3
Đó là khả năng mở rộng theo nghĩa là nó dễ dàng để thêm ký tự, không theo nghĩa hiệu suất ... :)
Guffa

2
À vâng, tất nhiên. Có lẽ "có thể mở rộng hơn" sẽ là một lựa chọn từ ngữ tốt hơn.
Jeff Mercado

Hiệu suất sẽ không khủng khiếp. Dù sao thì tốt hơn regexp được thông dịch.
Steven Sudit

Câu trả lời tuyệt vời chỉ để hoàn thiện bạn có thể chia chuỗi đến của mình thành một mảng trước, ví dụ: var splitStringArray = someString.Split (''); Sau đó, bạn có thể làm điều gì đó như: if (someStringArray.Any (s => otherString.Contains (s))) {// làm gì đó} Hy vọng điều đó sẽ giúp ai đó rõ ràng.
Tahir Khalid


21

Bạn có thể thử với biểu thức chính quy

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

1
+1, mặc dù vì anh ấy đang tìm kiếm các ký tự đơn lẻ nên giải pháp linq hoặc indexOfAny có thể hiệu quả hơn.
Joel Coehoorn

+1 cho biểu thức chính quy. đó là những gì tôi đã đi, nếu không có IndexOfAny
Stavros

1
Biểu thức chính quy là quá mức cần thiết cho điều này.
Steven Sudit,

3
Điều gì khiến mọi người nói rằng regexes là quá mức cần thiết cho việc này? Nếu regex được biên dịch một lần và sử dụng nhiều lần, và bạn có các chuỗi chỉ có c trong đó hoặc c gần đầu và a, b gần cuối, thì regex sẽ hiệu quả hơn nhiều.
bruceboughton

Nó không hoạt động với các ký tự đặc biệt như -, '"
.`

14

Nếu bạn cần ContainsAny với một cụ thể StringComparison(ví dụ: bỏ qua chữ hoa chữ thường) thì bạn có thể sử dụng phương thức String Extentions này.

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

Sử dụng với 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
Chỉ cần một lưu ý để cải thiện câu trả lời này. Bạn có thể viết nó thậm chí còn khó hiểu hơn với từ khóa params: ContainsAny (đầu vào chuỗi này, StringComparison so sánhType, chuỗi tham số [] chứaKeywords) và sử dụng như input.ContainsAny (chuỗi phụ, StringComparison.CurrentCultureIgnoreCase, "chuỗi", "nhiều chuỗi con" ... vv)
Roma Borodov

7

Đây là một "giải pháp đẹp hơn" và khá đơn giản

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

4

Vì một chuỗi là một tập hợp các ký tự, bạn có thể sử dụng các phương thức mở rộng LINQ trên chúng:

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

Thao tác này sẽ quét chuỗi một lần và dừng lại ở lần xuất hiện đầu tiên, thay vì quét chuỗi một lần cho mỗi ký tự cho đến khi tìm thấy khớp.

Điều này cũng có thể được sử dụng cho bất kỳ biểu thức nào bạn thích, ví dụ: kiểm tra một loạt các ký tự:

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

Đã đồng ý. Điều này giải quyết vấn đề quét nhiều lần khi các điều kiện đầu tiên không khớp. Bạn có thắc mắc không biết phía trên của lambda là gì? Không nên nhiều một lần.
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));
}

Anycho bất kỳ, Allcho mọi


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
Các phương thức HasWisedCharacters chấp nhận hai hoặc ba chuỗi. Chuỗi đầu tiên chúng tôi muốn kiểm tra các ký tự nhất định. Chuỗi thứ hai, tất cả các ký tự mà chúng ta sẽ tìm kiếm trong chuỗi đầu tiên. Phương thức nạp chồng cung cấp đầu ra cho người gọi (tức là Chính) dưới dạng một chuỗi thứ ba. Một câu lệnh foreach lồng nhau đi qua từng ký tự trong nguồn và so sánh từng ký tự; với những ký tự mà chúng tôi đang kiểm tra. Nếu một trong các ký tự được tìm thấy, nó sẽ trả về true. Phương thức được nạp chồng sẽ xuất ra một chuỗi ký tự được tìm thấy khớp với những ký tự được kiểm tra, nhưng sẽ không trả về cho đến khi hết tất cả. Hữu ích?
Nate Wilkins

1
Hãy bắt đầu một dự án bảng điều khiển C # và sao chép mã bên trong lớp chương trình - hãy đảm bảo thay thế phương thức chính. Tinker với hai chuỗi (goodUserName và badUserName) và bạn có thể thấy những gì các phương thức làm và cách chúng hoạt động. Các ví dụ dài hơn để cung cấp một giải pháp khả thi có thể được sửa đổi mà không có dấu phân cách như dấu phẩy. Các chuỗi thoát chỉ là một cách để đại diện cho một dấu ngoặc kép và dấu gạch chéo ngược nếu bạn cần kiểm tra chúng.
Nate Wilkins

1

Bạn có thể sử dụng Biểu thức chính quy

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

Bạn chắc chắn có thể, nhưng tôi không hiểu tại sao bạn lại muốn khi hầu hết mọi thứ khác tốt hơn.
Steven Sudit

0

Nếu bạn đang tìm kiếm các chuỗi tùy ý và không chỉ các ký tự, bạn có thể sử dụng quá tải IndexOfAny lấy đối số chuỗi từ dự án mới NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.