Dize işlemleri: Desen eşleştirme, performans ve span tabanlı arama

Bu makalede üç dize işlemi ele alınıyor: ile System.Text.RegularExpressions.Regexeşleşen normal ifade deseni, üzerinde ReadOnlySpan<T>ayırmasız arama ve doğru, hızlı karşılaştırmalar için bir StringComparison değer seçme.

Normal ifadeleri kullanarak belirli metinleri bulma

sınıfı dizelerde System.Text.RegularExpressions.Regex sabit alt dizeler yerine desenler arar. Statik Regex.IsMatch yöntem giriş dizesini, deseni ve isteğe bağlı RegexOptions bayrakları alır.

Aşağıdaki örnek, her tümcede veyabüyük/küçük harfe duyarsız sözcüğünü arar. Desen the(ir)?\s isteğe bağlı olarak ve ardından irbir boşluk karakteriyle eşleşirthe:

Pattern Meaning
the değişmez metinle eşleşme the
(ir)? eşleşme 0 veya 1 oluşumu ir
\s boşluk karakteriyle eşleştirme
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();
    }
}

Dizeleri bir desene göre doğrulama

Girişin tamamının bir şekille eşleşip eşleşmediğini denetlemek için deseni ve $ile ^ sabitleyebilirsiniz. Aşağıdaki örnek, her dizenin ABD stilinde bir telefon numarası olduğunu doğrular: üç basamak, üç basamak, dört basamak, tirelerle ayrılmış:

Pattern Meaning
^ dizenin başlangıcıyla eşleş
\d{3} tam olarak üç basamaklı karakter eşleştir
- sabit - karakter eşleştirme
\d{4} tam olarak dört basamaklı karakter eşleştir
$ dizenin sonuyla eşleş
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");
}

Tam desen söz dizimi için bkz. Normal ifade dili - hızlı başvuru.

Yöntemlerle normal ifadeler arasında string seçim yapma

string yöntemleri ve Regex çakışan sorunları çözme. Aradığınız metin değişmez değer, bilinen bir ön ek veya sonek ya da sabit sınırlayıcı olduğunda yöntemleri tercih edin string . Bir deseni derlemenin ve yürütmenin maliyetini ödemedikleri için okuması daha kolaydır ve daha hızlıdır. Regex Arama hedefinin şekil olduğu zamanlara (değişimler, isteğe bağlı gruplar, yinelenen karakter sınıfları veya bağlantılı doğrulama gibi) ulaşın. Genel bir kural olarak, aramayı bir veya iki string.Contains / / StartsWithIndexOf çağrı olarak yazabiliyorsanız, bunu yapın.

Kullanarak arama ReadOnlySpan<char>

Büyük girişleri ayrıştırdığınızda veya sık erişimli bir yolda arama çalıştırdığınızda ve çağrı başına ayırmaları string.Substringstring.Split baskın olabilir. ReadOnlySpan<char>kopyalamadan var olan bir dize (veya dizi veya yığın arabelleği) üzerinde bir görünüm sağlar ve MemoryExtensions dahil olmak üzere IndexOfyaygın string yöntemlerin span tabanlı eşdeğerlerini sağlar:

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

Dilimler (input[start..], ) yalnızca özgün karakterlerin üzerindeki pencereler olduğundan, rest[..end]span tabanlı arama ayırmaları önler. Aynı yaklaşım anahtar-değer listelerini, üst bilgileri ve diğer sınırlandırılmış metinleri çağırmadan Substringayrıştırmak için ölçeklendirilir.

Performansla ilgili dikkat edilmesi gerekenler StringComparison

Çoğu string örnek yönteminin bir StringComparison değeri kabul eden aşırı yüklemeleri vardır. Varsayılan olarak sıralı, ancak String.Compare(String, String)String.IndexOf(String)varsayılan olarak geçerli kültür gibi String.Equals(String) yöntemler. Bu fark iki şekilde önemlidir:

  • Hız. Sıralı karşılaştırma, sıkı, vektörleştirilmiş döngülerde çalışan bir bayt için bayt testidir. Kültüre duyarlı karşılaştırma bir sıralama tablosuna başvurur, karakterleri birleştirme adımlarını gösterir ve yerel ayara özgü kurallar uygular. Aynı giriş için daha yavaş bir büyüklük sırası olabilir.
  • Doğruluk. Kültüre duyarlı karşılaştırma, beklemediğiniz karakterleri katlayabilir (Türkçe i/I, Almancadan ßss, ligatürlere). Bu davranış, bir kullanıcının gördüğü adları sıralamak için uygundur, ancak tanımlayıcıları, yolları veya protokol belirteçlerini ayrıştırmada yanlıştır.

Dosya adları, URL'ler, HTTP üst bilgileri, tanımlayıcılar ve yapılandırma anahtarları gibi makine tanımlı metinler için geçiş StringComparison.Ordinal yapın veya StringComparison.OrdinalIgnoreCase açıkça yapın. Kullanıcılara gösterilen doğal dil metni için kültüre duyarlı değerleri ayırın. Kapsamlı yönergeler için bkz. .NET içindeki dizeleri karşılaştırmak için Best uygulamaları.

Ayrıca bakınız