Kiểm tra xem một chuỗi có chứa một trong 10 ký tự không


107

Tôi đang sử dụng C # và tôi muốn kiểm tra xem một chuỗi có chứa một trong mười ký tự, *, &, #, v.v.

cách tốt nhất là gì?


1
Bạn có muốn xem liệu có bất kỳ ký tự nào ở đó không hoặc liệu nó có chứa "một" (tức là: Chính xác là một) trong số các ký tự đó và chỉ một ký tự không?
Reed Copsey

Câu trả lời:


210

Sau đây là phương pháp đơn giản nhất, theo quan điểm của tôi:

var match = str.IndexOfAny(new char[] { '*', '&', '#' }) != -1

Hoặc ở dạng có thể dễ đọc hơn:

var match = str.IndexOfAny("*&#".ToCharArray()) != -1

Tùy thuộc vào ngữ cảnh và hiệu suất được yêu cầu, bạn có thể muốn hoặc không muốn lưu mảng char vào bộ nhớ cache.


Khi khởi tạo mảng char, kiểu có thể bị bỏ qua và nó sẽ được suy ra.
Palec

40

Như những người khác đã nói, hãy sử dụng IndexOfAny. Tuy nhiên, tôi sẽ sử dụng nó theo cách này:

private static readonly char[] Punctuation = "*&#...".ToCharArray();

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny(Punctuation) >= 0;
}

Bằng cách đó, bạn sẽ không phải tạo một mảng mới trên mỗi cuộc gọi. Chuỗi cũng dễ quét hơn một chuỗi các ký tự, IMO.

Tất nhiên nếu bạn chỉ sử dụng cái này một lần, vì vậy việc tạo lãng phí không phải là vấn đề, bạn có thể sử dụng:

private const string Punctuation = "*&#...";

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny(Punctuation.ToCharArray()) >= 0;
}

hoặc là

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny("*&#...".ToCharArray()) >= 0;
}

Nó thực sự phụ thuộc vào việc bạn thấy dễ đọc hơn, bạn có muốn sử dụng các ký tự dấu câu ở nơi khác hay không và tần suất phương thức sẽ được gọi.


CHỈNH SỬA: Đây là một phương pháp thay thế cho phương pháp của Reed Copsey để tìm hiểu xem một chuỗi có chứa chính xác một trong các ký tự hay không.

private static readonly HashSet<char> Punctuation = new HashSet<char>("*&#...");

public static bool ContainsOnePunctuationMark(string text)
{
    bool seenOne = false;

    foreach (char c in text)
    {
        // TODO: Experiment to see whether HashSet is really faster than
        // Array.Contains. If all the punctuation is ASCII, there are other
        // alternatives...
        if (Punctuation.Contains(c))
        {
            if (seenOne)
            {
                return false; // This is the second punctuation character
            }
            seenOne = true;
        }
    }
    return seenOne;
}

Tôi cho rằng nó đáng lưu vào bộ nhớ đệm mảng char nếu hiệu suất là vấn đề, nhưng một lần nữa, nó có thể không đáng giá tùy thuộc vào ngữ cảnh.
Noldorin 07/09/09

1
Có, nếu bạn chỉ sử dụng nó trong một phương thức sẽ được thực thi một khi nó có thể không đáng. Tuy nhiên, tôi nghĩ rằng nó cải thiện khả năng đọc cũng như hiệu suất. Tất nhiên, bạn có thể sử dụng ToCharArraybiểu mẫu "inline" nếu được yêu cầu.
Jon Skeet 07/09/09

1
@canon: Bộ lớn bao nhiêu? Đối với các bộ rất, rất nhỏ, tôi hy vọng Array.Contains sẽ nhanh hơn. Đối với bộ lớn, HashSet có khả năng để giành chiến thắng và đấm.
Jon Skeet

5

Nếu bạn chỉ muốn xem liệu nó có chứa bất kỳ ký tự nào không, tôi khuyên bạn nên sử dụng string.IndexOfAny, như được đề xuất ở những nơi khác.

Nếu bạn muốn xác minh rằng một chuỗi chứa chính xác một trong mười ký tự và chỉ một ký tự, thì nó sẽ phức tạp hơn một chút. Tôi tin rằng cách nhanh nhất sẽ là kiểm tra một Giao lộ, sau đó kiểm tra các bản sao.

private static char[] characters = new char [] { '*','&',... };

public static bool ContainsOneCharacter(string text)
{
    var intersection = text.Intersect(characters).ToList();
    if( intersection.Count != 1)
        return false; // Make sure there is only one character in the text

    // Get a count of all of the one found character
    if (1 == text.Count(t => t == intersection[0]) )
        return true;

    return false;
}

Vâng - Tôi cho rằng một vòng lặp đơn có lẽ nhanh hơn trong trường hợp này, đặc biệt là với một nhóm dấu câu nhỏ. Tôi rất tò mò muốn thử kiểm tra điều này với các chuỗi lớn để xem cái nào thực sự nhanh hơn.
Reed Copsey

1
Tôi nghĩ rằng việc tìm kiếm giao điểm của hai chuỗi dù sao cũng sẽ phải đi từng ký tự, vì vậy tôi không thể biết nó sẽ nhanh hơn như thế nào ... và tuyến đường được đề xuất của tôi không chỉ sử dụng một đường chuyền duy nhất mà còn có tùy chọn của một "sớm". Hãy tưởng tượng nếu văn bản có chiều dài một triệu ký tự, nhưng lần đầu tiên hai đều "*" :)
Jon Skeet


1
var specialChars = new[] {'\\', '/', ':', '*', '<', '>', '|', '#', '{', '}', '%', '~', '&'};

foreach (var specialChar in specialChars.Where(str.Contains))
{
    Console.Write(string.Format("string must not contain {0}", specialChar));
}

0

Cảm ơn tất cả các bạn! (Và chủ yếu là Jon!): Điều này cho phép tôi viết điều này:

    private static readonly char[] Punctuation = "$€£".ToCharArray();

    public static bool IsPrice(this string text)
    {
        return text.IndexOfAny(Punctuation) >= 0;
    }

vì tôi đang tìm kiếm một cách hay để phát hiện xem một chuỗi nhất định có thực sự là giá hay câu, chẳng hạn như 'Quá thấp để hiển thị'.


2
Tôi biết cách này đã cũ, nhưng phải nói rõ rằng đây không phải là cách đặc biệt tốt để so khớp tiền tệ ... Nếu bạn có ai đó viết "Ke $ ha", nó sẽ khớp như một mức giá ... Thay vào đó, hãy tham khảo một cách thích hợp để phát hiện tiền tệ được xác định tại đây: stackoverflow.com/questions/7214513/…
mcse3010
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.