Periksa apakah sebuah string berisi salah satu dari 10 karakter

107

Saya menggunakan C # dan saya ingin memeriksa apakah sebuah string berisi salah satu dari sepuluh karakter, *, &, # dll.

Apakah cara terbaiknya?

Jade M
sumber
1
Apakah Anda ingin melihat apakah ada karakter di sana, atau apakah itu berisi "satu" (yaitu: Tepat satu) dari karakter itu, dan hanya satu?
Reed Copsey

Jawaban:

210

Berikut ini akan menjadi metode paling sederhana, menurut saya:

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

Atau dalam bentuk yang mungkin lebih mudah dibaca:

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

Bergantung pada konteks dan kinerja yang diperlukan, Anda mungkin ingin atau tidak ingin men-cache array karakter.

Noldorin
sumber
Saat membuat instance array karakter, tipe dapat dihilangkan dan akan disimpulkan.
Palec
40

Seperti yang dikatakan orang lain, gunakan IndexOfAny. Namun, saya akan menggunakannya dengan cara ini:

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

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

Dengan cara itu Anda tidak akan membuat array baru pada setiap panggilan. String tersebut juga lebih mudah dipindai daripada serangkaian literal karakter, IMO.

Tentu saja jika Anda hanya akan menggunakan ini sekali, jadi kreasi yang terbuang tidak menjadi masalah, Anda dapat menggunakan:

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

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

atau

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

Ini sangat bergantung pada mana yang menurut Anda lebih mudah dibaca, apakah Anda ingin menggunakan karakter tanda baca di tempat lain, dan seberapa sering metode tersebut akan dipanggil.


EDIT: Berikut adalah alternatif metode Reed Copsey untuk mengetahui apakah sebuah string berisi persis salah satu karakter.

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;
}
Jon Skeet
sumber
Saya kira itu layak untuk menyimpan array karakter jika kinerja adalah masalah, tetapi sekali lagi itu mungkin tidak sepadan tergantung pada konteksnya.
Noldorin
1
Ya, jika Anda hanya menggunakannya dalam metode yang akan dijalankan setelah itu mungkin tidak sepadan. Namun, saya pikir ini meningkatkan keterbacaan serta kinerja. Anda dapat menggunakan ToCharArrayformulir "inline" jika diperlukan, tentunya.
Jon Skeet
1
@canon: Seberapa besar setnya? Untuk set yang sangat, sangat kecil, saya berharap Array.Contains lebih cepat. Untuk set besar, HashSet cenderung menang bermil-mil.
Jon Skeet
5

Jika Anda hanya ingin melihat apakah itu berisi karakter apa pun, saya sarankan menggunakan string.IndexOfAny, seperti yang disarankan di tempat lain.

Jika Anda ingin memverifikasi bahwa sebuah string berisi tepat satu dari sepuluh karakter, dan hanya satu, maka itu menjadi sedikit lebih rumit. Saya yakin cara tercepat adalah memeriksa titik-temu, lalu memeriksa duplikat.

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;
}
Reed Copsey
sumber
Ya - Saya kira satu putaran mungkin lebih cepat dalam kasus ini, terutama dengan set kecil tanda baca. Saya penasaran untuk mencoba menguji ini dengan string besar untuk melihat mana yang benar-benar lebih cepat.
Reed Copsey
1
Saya pikir menemukan perpotongan dari dua string harus berjalan karakter demi karakter, jadi saya tidak dapat melihat bagaimana itu akan lebih cepat ... dan rute yang saya sarankan tidak hanya menggunakan satu lintasan, tetapi juga memiliki pilihan "keluar awal". Bayangkan jika teks adalah satu juta karakter, tetapi dua yang pertama sama-sama "*" :)
Jon Skeet
4
String.IndexOfAny(Char[])

Berikut adalah dokumentasi Microsoft .

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

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

Terima kasih semuanya! (Dan Terutama Jon!): Ini memungkinkan saya untuk menulis ini:

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

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

saat saya sedang mencari cara yang baik untuk mendeteksi apakah string tertentu sebenarnya adalah harga atau kalimat, seperti 'Terlalu rendah untuk ditampilkan'.

BernardG
sumber
2
Saya tahu ini sudah kuno, tetapi untuk memperjelas ini bukan cara yang baik untuk mencocokkan mata uang ... Jika Anda meminta seseorang menulis "Ke $ ha", itu akan cocok sebagai harga ... Alih-alih mengacu pada satu cara yang tepat untuk mendeteksi mata uang yang ditentukan di sini: stackoverflow.com/questions/7214513/…
mcse3010