C# Regex ile Güçlü Metin İşleme: Desenleri Yakala ve Dönüştür
Giriş: Metin İşlemede C# Regex Gücü
Oyun geliştirme süreçlerinde, özellikle kullanıcı girdilerini işlerken, log dosyalarını analiz ederken veya belirli bir formatta veriyi ayrıştırırken metin işleme kaçınılmaz bir görevdir. Basit metin işlemleri için `string` sınıfının metotları yeterli olsa da, daha karmaşık desenleri aramak, eşleştirmek veya değiştirmek gerektiğinde C# Regex (Regular Expressions - Düzenli İfadeler) devreye girer. Bu makalede, C# Regex'in temellerinden başlayarak, ileri seviye kullanımlarına, pratik ipuçlarına ve yaygın hatalara değineceğiz. Unity projelerinizde metin işleme yeteneklerinizi bir üst seviyeye taşımak için bu güçlü aracı nasıl kullanacağınızı keşfedeceksiniz.
C# Regex Nedir ve Neden Kullanmalıyız?
Regex, metin içinde belirli arama desenlerini tanımlamak için kullanılan özel bir karakter dizisidir. Bu desenler sayesinde, metin içerisinde telefon numaraları, e-posta adresleri, URL'ler, belirli karakter grupları veya formatlanmış veriler gibi karmaşık yapıları kolayca bulabilir, doğrulayabilir veya değiştirebilirsiniz. C# dilinde `System.Text.RegularExpressions` namespace'i altında bulunan `Regex` sınıfı, bu işlemleri gerçekleştirmemizi sağlar.
Peki, neden `string` metotları yerine C# Regex kullanmalıyız? `string.Contains()`, `string.StartsWith()`, `string.Replace()` gibi metotlar basit senaryolar için harikadır. Ancak bir kullanıcının girdiği e-posta adresinin geçerli olup olmadığını kontrol etmek veya bir metinden tüm sayısal değerleri çekmek gibi durumlarda, bu metotlarla çok uzun ve hata yapmaya açık kodlar yazmanız gerekir. C# Regex, bu tür karmaşık desen eşleştirmelerini çok daha kısa, okunabilir ve güçlü bir şekilde yapmanıza olanak tanır.
Temel Regex Sözdizimi ve Desenler
Regex'in gücü, kullandığı özel karakterlerde ve bunların kombinasyonlarındadır. İşte bazı temel Regex karakterleri ve anlamları:
Karakter Sınıfları ve Miktarlar
- `.`: Herhangi bir karakterle eşleşir (yeni satır hariç).
- `\d`: Herhangi bir rakamla eşleşir (0-9).
- `\D`: Rakam olmayan herhangi bir karakterle eşleşir.
- `\w`: Herhangi bir kelime karakteriyle eşleşir (a-z, A-Z, 0-9, _).
- `\W`: Kelime karakteri olmayan herhangi bir karakterle eşleşir.
- `\s`: Herhangi bir boşluk karakteriyle eşleşir (boşluk, tab, yeni satır vb.).
- `\S`: Boşluk karakteri olmayan herhangi bir karakterle eşleşir.
- `[abc]`: 'a', 'b' veya 'c' karakterlerinden biriyle eşleşir.
- `[^abc]`: 'a', 'b' veya 'c' dışındaki herhangi bir karakterle eşleşir.
- `[a-z]`: 'a' ile 'z' arasındaki küçük harflerden biriyle eşleşir.
Miktar belirleyiciler (Quantifiers):
- `*`: Önceki karakterden sıfır veya daha fazla eşleşme.
- `+`: Önceki karakterden bir veya daha fazla eşleşme.
- `?`: Önceki karakterden sıfır veya bir eşleşme.
- `{n}`: Önceki karakterden tam olarak n eşleşme.
- `{n,}`: Önceki karakterden en az n eşleşme.
- `{n,m}`: Önceki karakterden en az n, en fazla m eşleşme.
Sınırlar ve Gruplama
- `^`: Satırın başlangıcıyla eşleşir.
- `$`: Satırın sonuyla eşleşir.
- `\b`: Kelime sınırı ile eşleşir.
- `\B`: Kelime sınırı olmayan bir konumla eşleşir.
- `(pattern)`: Bir grubu tanımlar. Eşleşen kısmı yakalar.
- `(?:pattern)`: Bir grubu tanımlar ancak eşleşen kısmı yakalamaz (non-capturing group).
- `|`: VEYA operatörü. Desenlerden biriyle eşleşir.
Örnek Desenler:
- `\d{3}-\d{3}-\d{4}`: Telefon numarası formatı (örn: 123-456-7890).
- `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`: Basit bir e-posta adresi.
- `^(\w+\s)*\w+$`: Sadece kelime ve boşluklardan oluşan bir satır.
C# İçinde Regex Kullanımı: `System.Text.RegularExpressions`
C# dilinde Regex kullanmak için `System.Text.RegularExpressions` namespace'ini projenize dahil etmeniz gerekir. Temel olarak `Regex` sınıfının statik metotlarını veya bir `Regex` nesnesi oluşturarak kullanabiliriz.
using System.Text.RegularExpressions; // Gerekli namespace`Regex.IsMatch()` ile Eşleşme Kontrolü
Bir metnin belirli bir desene uyup uymadığını kontrol etmek için kullanılır. `bool` bir değer döndürür.
string metin = "Merhaba Dünya!";
string desen = "Dünya";
bool eslestiMi = Regex.IsMatch(metin, desen);
Debug.Log($"Metin '{desen}' deseniyle eşleşiyor mu? {eslestiMi}"); // True
string email = "test@example.com";
string emailDesen = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
bool gecerliEmail = Regex.IsMatch(email, emailDesen);
Debug.Log($"'{email}' geçerli bir e-posta mı? {gecerliEmail}"); // True`Regex.Match()` ile İlk Eşleşmeyi Bulma
Bir metin içinde desene uyan ilk eşleşmeyi bulur ve bir `Match` nesnesi döndürür. `Match` nesnesi, eşleşen metni (`Value`), başlangıç indeksini (`Index`) ve yakalanan grupları (`Groups`) içerir.
string logMetni = "Hata: Kullanıcı 'ali' bulunamadı. Hata kodu: 404";
string hataDesen = @"Hata kodu: (\d+)";
Match eslesme = Regex.Match(logMetni, hataDesen);
if (eslesme.Success)
{
Debug.Log($"Eşleşen metin: {eslesme.Value}"); // Hata kodu: 404
Debug.Log($"Hata kodu: {eslesme.Groups[1].Value}"); // 404 (İlk yakalanan grup)
}`Regex.Matches()` ile Tüm Eşleşmeleri Yakalama
Bir metin içinde desene uyan tüm eşleşmeleri bulur ve bir `MatchCollection` nesnesi döndürür. Bu koleksiyon üzerinde döngü yaparak her bir eşleşmeye erişebilirsiniz.
string urunKodlari = "Ürün1: ABC-123, Ürün2: DEF-456, Ürün3: GHI-789";
string kodDesen = @"([A-Z]{3}-\d{3})";
MatchCollection tumEslesmeler = Regex.Matches(urunKodlari, kodDesen);
foreach (Match m in tumEslesmeler)
{
Debug.Log($"Bulunan ürün kodu: {m.Groups[1].Value}");
}
// Çıktı:
// Bulunan ürün kodu: ABC-123
// Bulunan ürün kodu: DEF-456
// Bulunan ürün kodu: GHI-789`Regex.Replace()` ile Metin Değiştirme
Bir metin içindeki desene uyan kısımları başka bir metinle değiştirmek için kullanılır.
string metin = "Kullanıcı adı: [username], Şifre: [password]";
string desen = "\[(username|password)\]";
string yeniMetin = Regex.Replace(metin, desen, "***GİZLİ***");
Debug.Log(yeniMetin); // Kullanıcı adı: ***GİZLİ***, Şifre: ***GİZLİ***
// Gruptaki değeri kullanarak değiştirme
string tarihMetni = "Bugün 2023-10-26 tarihidir.";
string tarihDesen = "(\d{4})-(\d{2})-(\d{2})";
// $3: 3. grup (gün), $2: 2. grup (ay), $1: 1. grup (yıl)
string yeniTarihMetni = Regex.Replace(tarihMetni, tarihDesen, "$3.$2.$1");
Debug.Log(yeniTarihMetni); // Bugün 26.10.2023 tarihidir.Pratik İpuçları ve İleri Seviye Kullanım
İpucu 1: `RegexOptions` ile Davranışı Özelleştirme
C# Regex işlemlerini daha esnek hale getirmek için `RegexOptions` numaralandırmasını kullanabilirsiniz. En yaygın kullanılanlar:
- `IgnoreCase`: Büyük/küçük harf duyarsız eşleşme.
- `Multiline`: `^` ve `$` işaretlerinin satır başı/sonuyla eşleşmesini sağlar, tüm metnin başı/sonu yerine.
- `Compiled`: Deseni önceden derler, tekrar tekrar kullanıldığında performansı artırır.
- `ExplicitCapture`: Sadece adlandırılmış veya numaralandırılmış grupları yakalar.
string metin = "apple Apple APPLE";
string desen = "apple";
// Büyük/küçük harf duyarsız eşleşme
MatchCollection eslesmeler = Regex.Matches(metin, desen, RegexOptions.IgnoreCase);
foreach (Match m in eslesmeler)
{
Debug.Log(m.Value); // apple, Apple, APPLE
}İpucu 2: Adlandırılmış Gruplar (Named Groups) Kullanımı
Desenlerinizde yakalamak istediğiniz kısımlara isim vermek, kodunuzu daha okunabilir ve yönetilebilir hale getirir. `(?<grupAdi>desen)` sözdizimi ile adlandırılmış grup oluşturulur.
string logEntry = "[INFO] 2023-10-26 14:30:15 - Kullanıcı 'Alice' giriş yaptı.";
string logDesen = "\[(?[A-Z]+)\] (?\d{4}-\d{2}-\d{2}) (?\d{2}:\d{2}:\d{2}) - (?.*)";
Match eslesme = Regex.Match(logEntry, logDesen);
if (eslesme.Success)
{
Debug.Log($"Seviye: {eslesme.Groups["Seviye"].Value}"); // INFO
Debug.Log($"Tarih: {eslesme.Groups["Tarih"].Value}"); // 2023-10-26
Debug.Log($"Mesaj: {eslesme.Groups["Mesaj"].Value}"); // Kullanıcı 'Alice' giriş yaptı.
} İpucu 3: Lookahead ve Lookbehind ile Daha Akıllı Eşleşmeler
Lookahead (`(?=...)`) ve Lookbehind (`(?<=...)`) yapıları, belirli bir desenin varlığını kontrol ederken, o deseni eşleşmenin bir parçası yapmadan sadece konum belirlemek için kullanılır. Bu, özellikle karmaşık senaryolarda çok faydalıdır.
- `(?=pattern)`: Pozitif Lookahead. Desenden sonra `pattern` geliyorsa eşleşir.
- `(?!pattern)`: Negatif Lookahead. Desenden sonra `pattern` gelmiyorsa eşleşir.
- `(?<=pattern)`: Pozitif Lookbehind. Desenden önce `pattern` geliyorsa eşleşir.
- `(?
string fiyatlar = "Elma 1.50 TL, Armut 2.00 USD, Portakal 1.75 TL";
// Sadece 'TL' ile biten fiyatları yakala
string desen = "\d+\.\d{2}(?= TL)";
MatchCollection tlFiyatlar = Regex.Matches(fiyatlar, desen);
foreach (Match m in tlFiyatlar)
{
Debug.Log(m.Value); // 1.50, 1.75
}Yaygın Hatalar ve Çözümleri
Aşırı Karmaşık Desenler
Yeni başlayanlar genellikle tek bir Regex deseniyle her şeyi yapmaya çalışır. Bu, deseni okunaksız, bakımı zor ve hatalara açık hale getirebilir. Mümkünse, daha basit desenleri birleştirin veya birden fazla `Regex` işlemi kullanın.
Özel Karakterleri Kaçırma (Escaping)
Regex sözdiziminde özel anlamı olan karakterler (örn: `.`, `*`, `+`, `?`, `(`, `)`, `[`, `]`, `{`, `}`, `\`, `^`, `$`, `|`) metin içinde tam olarak bu karakterleri aramak istediğinizde `\` ile kaçırılmalıdır. Örneğin, bir noktayı aramak için `\.` kullanmalısınız. C#’ta `Regex.Escape()` metodu, bir string içindeki tüm özel karakterleri otomatik olarak kaçırmak için kullanılabilir.
string metin = "Dosya adı: C:\\Program Files\\MyGame\\data.txt";
// Yanlış: . karakteri herhangi bir karakterle eşleşir
// string yanlisDesen = "data.txt";
// Doğru: . karakterini kaçırıyoruz
string dogruDesen = "data\\.txt";
bool eslesti = Regex.IsMatch(metin, dogruDesen);
Debug.Log($"Eşleşti mi (doğru desen)? {eslesti}"); // True
// Otomatik kaçırma
string arananKelime = "[item]";
string kacilmisDesen = Regex.Escape(arananKelime);
Debug.Log(kacilmisDesen); // \[item\]
Debug.Log(Regex.IsMatch("Bir [item] var.", kacilmisDesen)); // TruePerformans Sorunları (Greedy vs. Lazy)
Miktar belirleyiciler (quantifiers) varsayılan olarak "greedy" (açgözlü) çalışır, yani mümkün olan en uzun eşleşmeyi bulmaya çalışırlar. Bazen bu, beklenenden daha fazla metni yakalayabilir veya performans sorunlarına yol açabilir. Miktar belirleyicinin sonuna `?` ekleyerek "lazy" (tembel) hale getirebilirsiniz, bu durumda mümkün olan en kısa eşleşmeyi bulur.
- Greedy: `.*` (mümkün olan en uzun eşleşme)
- Lazy: `.*?` (mümkün olan en kısa eşleşme)
string htmlMetin = "<b>Kalın Yazı 1</b> ve <b>Kalın Yazı 2</b>";
// Greedy (yanlış sonuç)
string greedyDesen = "<b>.*</b>";
Match greedyEslesme = Regex.Match(htmlMetin, greedyDesen);
Debug.Log($"Greedy: {greedyEslesme.Value}");
// Çıktı: <b>Kalın Yazı 1</b> ve <b>Kalın Yazı 2</b> (Tüm metni yakalar)
// Lazy (doğru sonuç)
string lazyDesen = "<b>.*?</b>";
MatchCollection lazyEslesmeler = Regex.Matches(htmlMetin, lazyDesen);
foreach (Match m in lazyEslesmeler)
{
Debug.Log($"Lazy: {m.Value}");
}
// Çıktı:
// Lazy: <b>Kalın Yazı 1</b>
// Lazy: <b>Kalın Yazı 2</b>Performans ve Optimizasyon Notları
C# Regex güçlü bir araç olsa da, büyük metinlerde veya sık sık çalıştırıldığında performans üzerinde etkisi olabilir. İşte bazı optimizasyon ipuçları:
- `RegexOptions.Compiled` Kullanımı: Eğer aynı Regex desenini birden fazla kez kullanacaksanız, deseni bir kez derlemek için `RegexOptions.Compiled` seçeneğini kullanın. Bu, deseni derleme süresini başlangıçta artırsa da, sonraki eşleşme işlemlerini hızlandırır. Tek seferlik kullanımlarda bu seçeneği kullanmak aksine performansı düşürebilir.
- Basit İşlemler İçin `string` Metotları: Eğer yapacağınız işlem çok basitse (örn: bir kelimenin varlığını kontrol etmek, belirli bir karakteri değiştirmek), `string.Contains()`, `string.Replace()`, `string.IndexOf()` gibi standart `string` metotlarını tercih edin. Regex'in getirdiği ek yükten kaçınmış olursunuz.
- Desen Karmaşıklığını Azaltın: Çok karmaşık desenler, Regex motorunun daha fazla geri izleme (backtracking) yapmasına neden olabilir, bu da performansı olumsuz etkiler. Deseninizi mümkün olduğunca spesifik ve basit tutmaya çalışın.
- Girdi Boyutunu Sınırlayın: Regex'i çok büyük metin bloklarında çalıştırmaktan kaçının. Mümkünse, metni daha küçük parçalara ayırın ve her bir parçayı ayrı ayrı işleyin.
Sonuç
C# Regex, Unity projelerinizde metin işleme yeteneklerinizi önemli ölçüde artıran vazgeçilmez bir araçtır. Kullanıcı girdilerini doğrulamaktan, log dosyalarını analiz etmeye, karmaşık veri formatlarını ayrıştırmaya kadar birçok senaryoda size zaman ve emek kazandırır. Temel sözdizimini, C# içindeki kullanımını ve pratik ipuçlarını öğrenerek, metinler üzerinde tam kontrol sağlayabilir ve daha sağlam uygulamalar geliştirebilirsiniz. Unutmayın, pratik yapmak ve farklı desenlerle denemeler yapmak, C# Regex ustalığınızı geliştirmek için en iyi yoldur.
🧠 Ders Sonu Değerlendirme Testi
Dersi tamamladıktan sonra bilgilerinizi test edin ve ekstra puanlar kazanın.
Yorumlar (0)
İlk yorumu siz yapın!