Düzenli İfadelere (Regex) Pratik Giriş
C
Düzenli İfadelere (Regex) Pratik Giriş
Düzenli ifadeler (regular expressions, kısaca regex) ilk bakışta ^(\d{3})-(\d{4})$ gibi anlaşılmaz bir simge yığını gibi görünür. Oysa regex, "bir metnin belirli bir kalıba uyup uymadığını" tarif etmenin sıkıştırılmış bir dilidir. Yapı taşları aslında az sayıdadır; bir kez kavradığınızda e-posta doğrulamadan log ayıklamaya kadar her yerde işinize yarar.
Regex tam olarak neyi çözer?
Şu işleri düşünün: bir formdaki telefon numarasının geçerli olup olmadığını kontrol etmek, koca bir metinden tüm tarihleri çekip almak, bir dosyadaki tüm TODO satırlarını bulmak. Bunların hepsi "kalıp eşleştirme" problemidir ve regex tam da bunun için vardır.
JavaScript'te basit bir örnek:
const metin = "Sipariş no: 312-4455";
const kalip = /(\d{3})-(\d{4})/;
const sonuc = metin.match(kalip);
console.log(sonuc[0]); // "312-4455"
console.log(sonuc[1]); // "312" (ilk grup)
Temel yapı taşları
Düz karakterler kendileriyle eşleşir: kedi kalıbı metindeki "kedi" kelimesini bulur.
Karakter sınıfları bir grup olasılığı temsil eder:
\d→ bir rakam (0-9)\w→ bir harf, rakam veya alt çizgi\s→ bir boşluk karakteri.→ herhangi bir karakter (yeni satır hariç)[a-f]→ a'dan f'ye herhangi bir harf[^0-9]→ rakam olmayan herhangi bir karakter
Niceleyiciler "kaç kez" sorusunu yanıtlar:
*→ sıfır veya daha fazla+→ bir veya daha fazla?→ sıfır veya bir (yani isteğe bağlı){3}→ tam olarak 3 kez{2,5}→ 2 ile 5 kez arası
Çapalar (anchors) konumu belirtir:
^→ satırın başı$→ satırın sonu\b→ kelime sınırı
Aşağıdaki görsel, tek bir kalıbın parçalarının nasıl bir araya geldiğini gösteriyor:

Gruplar ve yakalama
Parantezler ( ) hem bir parçayı gruplar hem de o kısmı "yakalar" (capture), yani sonradan erişebilmeniz için saklar. Üstteki örnekte (\d{3}) ve (\d{4}) iki ayrı grup oluşturur; match sonucunda bunlara sonuc[1] ve sonuc[2] ile ulaşırsınız.
Yakalamaya ihtiyacınız yoksa (?:...) ile "yakalamayan grup" kullanın; bu hem niyetinizi belli eder hem de performansı bir nebze iyileştirir.
İsimli gruplar okunabilirliği artırır:
const kalip = /(?<alan>\d{3})-(?<no>\d{4})/;
const { groups } = "312-4455".match(kalip);
console.log(groups.alan); // "312"
console.log(groups.no); // "4455"
Sık yapılan hatalar
1. Açgözlü (greedy) eşleşme. .* mümkün olan en uzun parçayı yakalar. <b>kalın</b> içinde <.*> kalıbı tüm satırı yutar. Bunun yerine "tembel" sürümü <.*?> kullanın; en kısa eşleşmeyi alır.
2. Özel karakterleri kaçırmamak. ., +, *, ?, (, ) gibi karakterler özel anlam taşır. Gerçek bir nokta aramak istiyorsanız \. yazmalısınız. Örneğin dosya uzantısı için \.jpg$.
3. Her şeyi regex ile çözmeye çalışmak. HTML veya JSON gibi iç içe geçmiş yapıları regex ile ayrıştırmak kırılgandır. Bu işler için uygun bir ayrıştırıcı (parser) kullanın. Regex; satır, kelime ve basit kalıplar için parlar.
Faydalı birkaç hazır kalıp
// Basit e-posta (mükemmel değil ama çoğu durum için yeterli)
/^[\w.+-]+@[\w-]+\.[\w.-]+$/
// Baştaki/sondaki boşlukları bulma
/^\s+|\s+$/g
// Bir metindeki tüm hashtag'ler
/#\w+/g
// Türkçe karakterler dahil bir kelime
/[a-zçğıöşü]+/i
Sonundaki bayraklara dikkat edin: g (global) tüm eşleşmeleri bulur, i (insensitive) büyük/küçük harf ayrımını kaldırır.
Nasıl pratik yapmalı?
Regex öğrenmenin en hızlı yolu denemektir. regex101.com gibi araçlar, yazdığınız kalıbı anlık olarak test eder ve her parçanın ne işe yaradığını açıklar. Önce küçük kalıplarla başlayın, sonra parçaları birleştirin.
Sonuç
Regex, az sayıda yapı taşının birleşmesinden oluşan güçlü bir mini dildir: karakter sınıfları "ne", niceleyiciler "kaç kez", çapalar "nerede" sorusunu yanıtlar. Açgözlü eşleşme ve kaçış karakterleri gibi birkaç tuzağı bilirseniz, günlük metin işleme işlerinin büyük kısmını tek satırla halledebilirsiniz. Korkutucu görünen o simge dizisi, aslında düşündüğünüzden çok daha okunabilir.
Ek Görseller