Düzenli İfadeleri Korkmadan Kullanmak: Pratik Kalıplar ve Tuzaklar

Düzenli İfadeleri Korkmadan Kullanmak: Pratik Kalıplar ve Tuzaklar

Regex okunmaz bir yazı değildir; birkaç kalıbı ve üç tuzağı bilmek çoğu günlük ihtiyacı karşılar.

Düzenli ifadeler (regex), geliştiricilerin en çok çekindiği araçlardan biridir. Sebep çoğunlukla ilk karşılaşmadır: internetten kopyalanmış, kırk karakterlik, anlaşılmaz bir desen. Oysa günlük işlerin büyük kısmı, on kadar temel yapı taşıyla karşılanır. Bu yazıda korkuyu azaltan kalıpları ve gerçekten tehlikeli olan üç tuzağı ele alıyoruz.

Regex kullanım kuralları
Regex bir programlama dili değildir; yapısı olan veriyi ayrıştırmak için uygun değildir.

Günlük işleri karşılayan temel yapılar

Aşağıdaki yapılar, pratikte karşılaşılan ihtiyaçların çoğunu kapsar:

  • \d rakam, \w harf/rakam/alt çizgi, \s boşluk karakteri.
  • + bir veya daha fazla, * sıfır veya daha fazla, ? isteğe bağlı.
  • {2,4} en az iki en fazla dört tekrar.
  • ^ başlangıç, $ bitiş — doğrulamada kritiktir.
  • [abc] karakter kümesi, [^abc] bunların dışındakiler.
  • (...) yakalama grubu, (?:...) yakalamayan grup.

Doğrulamada en sık yapılan hata, başlangıç ve bitiş çapalarını unutmaktır: /\d{5}/ ifadesi, "abc12345xyz" içinde de eşleşir. Beş haneli bir kod doğrulamak istiyorsanız desen /^\d{5}$/ olmalıdır.

Açgözlü ve tembel eşleşme

En sık karşılaşılan "neden çalışmıyor?" durumu budur. .* varsayılan olarak açgözlüdür: mümkün olan en uzun eşleşmeyi alır.

Kod
$metin = '<b>birinci</b> ve <b>ikinci</b>';

preg_match('/<b>(.*)<\/b>/', $metin, $m);
// $m[1] = "birinci</b> ve <b>ikinci"   ← beklenmedik

preg_match('/<b>(.*?)<\/b>/', $metin, $m);
// $m[1] = "birinci"                      ← tembel eşleşme

Kural basittir: iki sınırlayıcı arasındaki içeriği alıyorsanız neredeyse her zaman tembel (*?) sürümü istersiniz.

Türkçe metin ve Unicode

Türkçe içerikte en sık yaşanan sorun, çok baytlı karakterlerin yanlış işlenmesidir. PHP'de u bayrağı kullanılmadığında desen baytlar üzerinde çalışır ve ğ, ş, İ gibi karakterler bölünebilir.

Kod
preg_replace('/[^a-zçğıöşü0-9]+/u', '-', mb_strtolower($baslik, 'UTF-8'));

Ayrıca büyük "İ" harfinin küçültülmesinde ortaya çıkan birleşik nokta karakteri, karşılaştırmalarda sessiz eşleşme kayıplarına yol açar. Metin karşılaştıran her yerde bu normalleştirmeyi yapmak gerekir — Türkçe metin işlemede en sık atlanan ayrıntıdır.

Üç gerçek tuzak

1. Yapısal veriyi regex ile ayrıştırmak

HTML, XML ve JSON iç içe geçebilen yapılardır; regex ise bu tür yapıları güvenilir biçimde çözemez. Basit durumlarda çalışan desen, gerçek veriyle karşılaştığında sessizce yanlış sonuç üretir. Doğru araç bir ayrıştırıcıdır. Regex burada yalnızca hızlı ve tek seferlik işler için kabul edilebilir.

2. Felaket geri izleme (performans)

İç içe tekrar içeren desenler ((a+)+$ gibi), belirli girdilerde üstel sürede çalışır ve tek bir istek sunucuyu kilitleyebilir. Kullanıcı girdisi üzerinde çalışan desenlerde bu, gerçek bir hizmet dışı bırakma riskidir. Korunma yolu, iç içe belirsiz tekrarlardan kaçınmak ve mümkünse çalışma süresine sınır koymaktır.

3. Kullanıcı girdisini desen olarak kullanmak

Arama kutusundan gelen metni doğrudan desenin içine koymak iki soruna yol açar: kullanıcı özel karakter girdiğinde desen bozulur ve kasıtlı bir girdiyle performans saldırısı yapılabilir. Girdi mutlaka kaçış işlemine tabi tutulmalıdır (preg_quote()). Bu, web uygulama güvenliği yazımızdaki "kullanıcı girdisine asla güvenme" ilkesinin bir uygulamasıdır.

Okunabilirlik: yorumlu desen

Uzun desenler tek satırda okunmaz. Genişletilmiş kip (x bayrağı) boşlukları yok sayar ve yorum yazmaya izin verir:

Kod
$desen = '/
    ^(\d{4})      # yıl
    -(\d{2})      # ay
    -(\d{2})$     # gün
/x';

Alternatif olarak isimlendirilmiş gruplar ((?<yil>\d{4})) kullanmak, sonuca $m[1] yerine $m['yil'] ile erişmeyi sağlar ve kodu belirgin biçimde okunur kılar.

Ne zaman regex kullanmamalı?

Basit bir alt dize kontrolü için str_contains(), ön ek kontrolü için str_starts_with() hem daha okunur hem daha hızlıdır. E-posta doğrulaması için ise elle yazılmış bir desen yerine dilin kendi doğrulama fonksiyonlarını kullanmak neredeyse her zaman daha doğrudur — e-posta biçimi, sanılandan çok daha karmaşık bir standarda dayanır.

Genel kural şudur: regex, desen aramak için iyidir; yapı ayrıştırmak için değil. PHP tarafındaki sık hatalar için PHP hataları rehberimize, desen sözdiziminin ayrıntıları için MDN düzenli ifadeler rehberine bakabilirsiniz.

Sonuç

Düzenli ifadeler, birkaç temel yapı taşı ve üç tuzak öğrenildiğinde korkulacak bir araç olmaktan çıkar: çapaları unutmamak, tembel eşleşmeyi bilmek, Unicode bayrağını kullanmak, yapısal veriyi ayrıştırıcıya bırakmak ve kullanıcı girdisini kaçırmak. Bu beş madde günlük ihtiyaçların neredeyse tamamını güvenle karşılar. Bugün kod tabanınızda küçük bir arama yapın: u bayrağı olmadan yazılmış kaç desen var? Türkçe metinle çalışan her biri, sessizce yanlış sonuç üretme adayıdır.

İlgili Yazılar

Beğeniniz benzer içerikleri öne çıkarmamıza yardımcı olur.

Sık Sorulan Sorular

Genellikle hayır. Standart e-posta biçimi sanıldığından karmaşıktır ve elle yazılan desenler geçerli adresleri reddeder. Dilin kendi doğrulama fonksiyonunu kullanmak daha doğru sonuç verir.

Basit desenler pratikte sorun çıkarmaz. Risk, iç içe belirsiz tekrar içeren desenlerdedir; bunlar belirli girdilerde üstel sürede çalışır ve kullanıcı girdisi üzerinde çalışıyorsa gerçek bir hizmet kesintisi riski oluşturur.

HTML iç içe geçebilen bir yapıdır ve düzenli ifadeler bu tür yapıları güvenilir biçimde çözemez. Basit örneklerde çalışan desen, gerçek veriyle sessizce yanlış sonuç üretir; doğru araç bir ayrıştırıcıdır.

En sık sebep Unicode bayrağının (/u) unutulmasıdır; desen bayt düzeyinde çalışır ve çok baytlı harfleri böler. Ayrıca büyük "İ" küçültülürken oluşan birleşik nokta karakteri karşılaştırmaları bozar.

S
superadmin

Bu yazıyı hazırladı. Sorularınız için iletişim sayfasından ulaşabilirsiniz.

Yorumlar (0)

Bu yazıya henüz yorum yapılmamış. İlk yorumu siz yazın!

Yorum Yaz

Yorumunuz onaylandıktan sonra yayınlanır. Ekibimiz gerekirse konuyla ilgili bir yanıt da paylaşır.

En az 10 karakter.