Bir Bilgisayar Mühendisi İçin Programlama Dili, Öğrendiklerini Sınadığı, Deneyler Yaptığı Bir Laboratuardır. Ve Mühendisler Deneylerini, Kestiremedikleri Sonuçları Gözlemlemek İçin Değil, Öngördükleri Sonuçları Doğrulamak İçin Yaparlar...
Programlama Günlüğü > Php Dili > preg_replace_callback, e Değiştiricisi ve Rekürsiyon
preg_replace_callback, e Değiştiricisi ve Rekürsiyon
   Düzenli ifadeler, genelde girmekten kaçınılan geniş kapsamlı bir konu. İlerde vereceğim örnek bunun sebebini açıkça ortaya koyacak. Ancak pekçok dil tarafından benzer kullanım biçimleri ile sunulan düzenli ifade eşleştirme/yer değiştirme fonksiyonları bizi onlarca satırlık koddan kurtarıp, problemimizin çözümünü birkaç satıra kadar kısaltabilir. Bu yüzden bu fonksiyonları tanıdığımdan beri, onlara hayranlık duyuyorum.

   İnternette düzenli ifadeler ile ilgili yığınla bilgi bulunduğu için bu konuya fazla girmeyeceğim. Asıl konumuz callback, e değiştiricisi ve rekürsiyon.

Kısaca Rekürsiyon (Recursion)
   Rekürsiyon, fonksiyonların kendilerilerini çağırmaları ile oluşturulur. Bir çeşit döngüye benzetilebilir. Bu yaklaşım, kendi çıktılarını girdi olarak kullanabilen fonksiyonlarla tasarlanan algoritmalarda çokça kullanılır. En basit ve belki de en açıklayıcı örnek faktöryel hesabının rekürsif çözümüdür...

   Tüm rekürsif fonksiyonların mutlaka birer geri dönüş noktası bulundurma zorunluluğu gözardı edilmemelidir. Aksi halde bu fonksiyonlar, çağrıları tutan yığın dolana kadar kendilerini çağırmaya devam ederler...

Geriçağırım(Callback) Parametresi
   PHPde callback parametresi alan birçok fonksiyon var. Callback parametresi, bu parametreyi alan fonksiyon tarafından çağırılacak olan fonksiyonun ismidir. Bu parametreler verilirken genelde create_function fonksiyonu kullanılır.

create_function() Fonksiyonu
   create_function fonksiyonu, isimsiz fonksiyonlar oluştur ve bu fonksiyonları simgeleyen string tipinde benzersiz değerler döndürür. Böylece direkt olarak callback parametresi yerine yazılabilir. Davranış açısından normal bir fonksiyondan farkı yoktur. Kullanımı aşağıdaki gibidir:
<?php
// string create_function(string Argümanlar, string Kod)
$fonksiyon = create_function('$a,$b,$c', 'return $a+$b+$c');
echo $fonksiyon(13,14,15);
// Çıktı: 42
?>

Perl Uyumlu Düzenli İfadelerde e Şablon Değiştiricisisi
   PHPnin preg_replace fonksiyonu kullanılarak, eşleşen değerin işlenip yerine konması istenebilir. Bu durumda iki farklı yöntem kullanılabilir. Birincisi, preg_replace_callback fonksiyonu, ikincisi de preg_replace fonksiyonunda e değiştiricisini kullanmak. Bu iki yöntem de tamamen aynı işlevi görür. Ama kullanımları farklıdır. Aşağıdaki örnekte her iki yöntem de örneklenmiştir...

   Gelelim örneğimize. Yazıya ekleyecek kapsamlı bir örnek düşünürken aklıma şu geldi: Elimizde bir html dosyası olsun. Bu dosyada bir tablo var ve tablodaki her hücrede cümleler var. Ancak bu cümleleri yazan adam büyük-küçük harflere hiç dikkat etmeden yazmış. Biz bu html sayfada hücreler içerisinde bulunan cümlelerdeki kelimelerin ilk harflerini büyük, sonrakileri küçük harflere dönüştürelim. (İtiraf etmeliyim ki bu soruyu çözene kadar canım çıktı)
<?php
$html = '
<html>
<head>
<meta http-equiv="Content-Type" content="text-html; charset=iso-8859-9">
<title>Deneme</title>
</head>
<body>
<p>Burada her türlü html etiketi, yazı olabilir...</p>
<table>
<tr><td style="width:200;">eŞleŞTirme vE Yer DEĞiştiRME.</td><td>DiĞer süTUN.</td></tr>
<tr><td>BuRAda BöYLe BiR SüRÜ saTıR vE SüTUn VaR.</td><td>
HatTa, HücRelerdekİ YaZIlaR<br>AşaĞIya Da KAYMıŞ OlaBilir.</td></tr>
</table>
</body>
</html>
';

$html = mb_strtolower($html,"iso-8859-9"); //Tümünü Türkçe desteği ile küçük harfe çeviriyoruz.

// Yöntem1: Rekürsiyon ve e değiştiricisi ----------
function rekursifFonk($girdi)
{
    $dIfade = "_\<td(.*?)\>(|\r\n|.*?\040)([a-z]{1})(.*?)(\040|)\</td\>_s";
    $yeniDeger = "stripslashes('<td$1>$2'.mb_strtoupper('$3','iso-8859-9').
                                          mb_strtolower('$4','iso-8859-9').'</td>')";
    if(is_array($girdi))
    {
        $yeniGirdi = '<td'.$girdi[1].'>'.$girdi[2].mb_strtoupper($girdi[3],'iso-8859-9').
                                                   mb_strtolower($girdi[4],'iso-8859-9').'</td>';
        $girdi= preg_replace($dIfade."e", $yeniDeger, $yeniGirdi);
    }
    return preg_replace_callback($dIfade, "rekursifFonk", $girdi);
}
echo rekursifFonk($html);
//--------------------------------------------------

/*
// Yöntem2: Döngü ve e Değiştiricisi ---------------
while(preg_match("_\<td.*?\>(|\r\n|.*?\040)[a-z]{1}.*?(\040|)\</td\>_es", $html))
    $html=preg_replace("_\<td(.*?)\>(|\r\n|.*?\040)([a-z]{1})(.*?)(\040|)\</td\>_es",
                       "stripslashes('<td$1>$2'.mb_strtoupper('$3','iso-8859-9').
                       mb_strtolower('$4','iso-8859-9').'</td>')", $html);
echo $html;
//--------------------------------------------------
*/
?>

   Başta, rekürsif yaklaşımın döngülere benzediğini yazmıştım. Örnekte 2. yöntem bir rekürsif fonksiyon ile yerine getirilebilecek olan işlevi döngü kullanarak yerine getirir. Aslında rekürsif yaklaşımlar kodları büyük oranda kısaltır. Örnekte kodların uzaması, rekürsiyonu sağlayan çağrının direkt rekürsif fonksiyon tarafından değil de, bu fonksiyonun çağırdığı bir başka fonksiyon tarafından yapılmasından kaynaklanır. Yani bu örnekte fonksiyon, kendisini çağıracak fonksiyonu çağırarak dolaylı olarak kendini çağırmış olur.  Her iki yöntem yerine kullanılabilecek hepsinden kısa ancak hepsinden karmaşık 3. bir yöntem daha düşünülebilir. preg_replace fonksiyonu e değiştiricisi ile birlikte uygun parametreler verilerek bir başka preg_replace fonksiyonunun içine yazılabilir. İçiçe iki preg_replace fonksiyonu tek ve çift tırnak karakterlerinde çözülmesi güç bir karmaşaya neden olacağı için bu fikri örneklemeye kalkışmıyorum bile...

   Son olarak düzenli ifadeyi ve anlamını da yazayım:
Düzenli İfade: \<td(.*?)\>(|\r\n|.*?\040)([a-z]{1})(.*?)(\040|)\</td\>
Anlamı       :  <td(herhangi bir uzunlukta karakter dizisi:$1)>(Ya hiçbir karakter olmasın ya alt satır geçişi olsun ya da herhangi bir uzunlukta karakter dizisi ve ardından boşluk:$2)(a-z arası karakterlerden herhangi bir tanesi:$3)(herhangi bir uzunlukta karakter dizisi:$4)(ya boşluk ya da hiçbir şey)</td>

 
Okunma Sayısı: 241
Yayınlanma Tarihi: 01 Mayıs 2010 Cumartesi - 16:44
Anahtar Kelimeler: düzenli ifade, değiştirici, modifier, replace, yer değiştirme, rekürsiyon, rekürsif, callback, geriçağırım, modifier, değiştirici, recursion, preg_replace, preg_replace_callback

Onaylı yorum bulunmuyor.
Yorum/Görüş Bildir
Yorumları html kodu veya özel karakter kullanmadan, yazım kurallarına
dikkat ederek ve düzgün bir Türkçe kullanarak yazalım...
 
      Atasoy Blog v3.0 © 2009-2010 Hüseyin Atasoy | Tema Tasarımı: Hüseyin Atasoy
AtasoyWeb Firefox'u Önerir :) | Yukarı Çık