Operasi string: Pencocokan pola, performa, dan pencarian berbasis rentang

Artikel ini membahas tiga operasi string: pencocokan pola ekspresi reguler dengan System.Text.RegularExpressions.Regex, pencarian bebas alokasi atas ReadOnlySpan<T>, dan memilih nilai untuk perbandingan yang StringComparison benar dan cepat.

Menemukan teks tertentu dengan menggunakan ekspresi reguler

Kelas System.Text.RegularExpressions.Regex mencari string untuk pola daripada substring tetap. Metode statis Regex.IsMatch mengambil string input, pola, dan bendera opsional RegexOptions .

Contoh berikut mencari setiap kalimat untuk kata atau, tidak peka huruf besar/kecil. Pola the(ir)?\s cocok the secara opsional diikuti oleh ir, lalu karakter spasi kosong:

Pola Meaning
the mencocokkan teks harfiah the
(ir)? kecocokan 0 atau 1 kemunculan ir
\s cocok dengan karakter spasi kosong
string[] sentences =
[
    "Put the water over there.",
    "They're quite thirsty.",
    "Their water bottles broke."
];

string pattern = @"the(ir)?\s";

foreach (string s in sentences)
{
    Console.Write($"{s,28}");

    if (Regex.IsMatch(s, pattern, RegexOptions.IgnoreCase))
    {
        Console.WriteLine($"  (match for '{pattern}' found)");
    }
    else
    {
        Console.WriteLine();
    }
}

Memvalidasi string terhadap pola

Untuk memeriksa apakah seluruh input cocok dengan bentuk, jangkar pola dengan ^ dan $. Contoh berikut memvalidasi bahwa setiap string adalah nomor telepon gaya AS: tiga digit, tiga digit, empat digit, dipisahkan oleh tanda hubung:

Pola Meaning
^ cocok dengan awal string
\d{3} cocok persis dengan tiga karakter digit
- cocok dengan karakter harfiah -
\d{4} cocok dengan tepat empat karakter digit
$ cocok dengan akhir string
string[] numbers =
[
    "123-555-0190",
    "444-234-22450",
    "690-555-0178",
    "146-893-232",
    "146-555-0122",
    "4007-555-0111",
    "407-555-0111",
    "407-2-5555",
    "407-555-8974",
    "407-2ab-5555",
    "690-555-8148",
    "146-893-232-"
];

string pattern = """^\d{3}-\d{3}-\d{4}$""";

foreach (string s in numbers)
{
    Console.Write($"{s,14}");
    Console.WriteLine(Regex.IsMatch(s, pattern) ? " - valid" : " - invalid");
}

Untuk sintaks pola lengkap, lihat Bahasa ekspresi reguler - referensi cepat.

Memilih antara string metode dan ekspresi reguler

string Regex dan menyelesaikan masalah yang tumpang tindih. Lebih suka string metode ketika teks yang Anda cari adalah nilai harfiah, awalan atau akhiran yang diketahui, atau pemisah tetap. Mereka lebih mudah dibaca dan lebih cepat, karena mereka tidak membayar biaya kompilasi dan menjalankan pola. Regex Jangkauan saat target pencarian adalah bentuk, seperti pergantian, grup opsional, kelas karakter berulang, atau validasi berlabuh. Sebagai aturan praktis, jika Anda dapat menulis pencarian sebagai satu atau dua string.Contains / / StartsWithIndexOf panggilan, lakukanlah.

Mencari menggunakan ReadOnlySpan<char>

Saat Anda mengurai input besar atau menjalankan pencarian di jalur panas, alokasi string.Substring per panggilan dan string.Split dapat mendominasi. ReadOnlySpan<char> memberi Anda tampilan atas string yang ada (atau array, atau buffer tumpukan) tanpa menyalin, dan MemoryExtensions menyediakan setara berbasis rentang dari metode umum string , termasuk IndexOf:

ReadOnlySpan<char> input = "key1=alpha;key2=beta;key3=gamma".AsSpan();
ReadOnlySpan<char> needle = "key2=".AsSpan();

int start = input.IndexOf(needle);
if (start >= 0)
{
    ReadOnlySpan<char> rest = input[(start + needle.Length)..];
    int end = rest.IndexOf(';');
    ReadOnlySpan<char> value = end >= 0 ? rest[..end] : rest;
    Console.WriteLine($"key2 = {value}");
}
// => key2 = beta

Pencarian berbasis rentang menghindari alokasi karena irisan (input[start..], rest[..end]) hanyalah jendela di atas karakter asli. Pendekatan yang sama menskalakan untuk mengurai daftar nilai kunci, header, dan teks berbatas lainnya tanpa pernah memanggil Substring.

Pertimbangan performa untuk StringComparison

Sebagian besar string metode instans memiliki kelebihan beban yang menerima StringComparison nilai. Metode seperti String.Equals(String) default ke ordinal, tetapi String.Compare(String, String) dan String.IndexOf(String) default ke budaya saat ini. Perbedaan ini penting dalam dua cara:

  • Kecepatan. Perbandingan ordinal adalah uji byte-for-byte yang berjalan dalam perulangan yang ketat dan vektor. Perbandingan sadar budaya berkonsultasi dengan tabel pengurutan, berjalan menggabungkan karakter, dan menerapkan aturan khusus lokal. Untuk input yang sama, itu bisa menjadi urutan besarnya lebih lambat.
  • Ketepatan. Perbandingan sadar budaya dapat melipat karakter yang tidak Anda harapkan (Bahasa Turki i/I, Jerman ß hingga ss, ligatur). Perilaku ini tepat untuk mengurutkan nama yang dilihat pengguna tetapi salah untuk mengurai pengidentifikasi, jalur, atau token protokol.

Untuk teks yang ditentukan mesin, seperti nama file, URL, header HTTP, pengidentifikasi, dan kunci konfigurasi, teruskan StringComparison.Ordinal atau StringComparison.OrdinalIgnoreCase eksplisit. Cadangkan nilai sadar budaya untuk teks bahasa alami yang ditunjukkan kepada pengguna. Untuk panduan komprehensif, lihat praktik Best untuk membandingkan string dalam .NET.

Baca juga