PHP

PHP ile regular expression (regex)

Regular expression (regex) Türkçesiyle düzenli ifadelermetinlerde bir biçimsel dil kullanarak tarif edilen kısımları seçip ayırmamıza yarayan bir programdır.

Neredeyse bütün programlama dillerinde kullanılan regex ile metinlerde ayrıştırmak istediğiniz her şeye ulaşabilirsiniz.

Örneğin günümüzde en çok içerik çalma botlarında kullanılır. Fakat yazı düzeni sağlamak ya da metinlerde aranan ifadelere ulaşıp onları manipüle etmek için de kullanabilirsiniz.

Bu yazıda öncelikle regex desenlerini denemek için bir kaç kullanışlı site paylaşacağım, sonrasında temel ihtiyaçları karşılayacak ve en çok kullanılan regex desenlerinden ve bunları PHP ile nasıl kullanacağımızdan bahsetmeye çalışacağım.

Giriş

Yazı boyunca göstereceğim desenleri deneyebilmek için anlık işlemler yapabilen ve her regex çalışmamızda tarayıcımızın bir tabında açık olması gereken bu siteleri mutlaka yer imlerinize ekleyin.

Hoşumuza giden bir tanesini açın ve verilen örnekleri canlı bir şekilde deneyerek daha iyi kavrayın.

Bir kelime aramak

Regex ile yapılabileğimiz en basit işlem kelime aramaktır, bunun için direkt aramak istediğimiz kelimeyi yazmak yeterli. Örnek olarak düzenli ifademize “elma” yazıyoruz. Ve elde edeceğimiz sonuçta elma kelimelerinin seçildiğini görebilirsiniz.

Örnek düzenli ifade:

elma

Metin ve sonuç:

Bu deneme amaçlı yazılmış ve içerisinde elma geçen öylesine bir metin.

Yukarıda sarı renkle işaret edilen kelime, yazdığımız ifadenin yakaladığı kelimenin göstergesidir. Bundan sonraki örneklerde de elde ettiğimiz sonuçları böyle göstereceğim.

Özel karakterler

Düzenli ifadelerde bolca anlam ve ifade içeren özel karakterler vardır. Asıl yapmak istediklerimizi bunlarla ifade edip istenilen sonuca ulaşırız. Öncelikle bu karakterlerin ne olduklarına bakalım, sonrasında da nasıl kullanıldıklarını örnekler ile deneyelim.

Düzenli ifadelerde kullanılan özel karakterler:

Karakter Açıklaması
d Herhangi bir rakamı ifade eder
. Satır başı hariç herhangi bir karakteri ifade eder
w Herhangi bir harfi, rakamı veya alt tireyi ifade eder
s Herhangi bir görünmez karakteri ve boşluğu ifade eder. (Boşluk, tab, satır başı gibi)
^ Başlangıcı ifade eder
$ Sonu ifade eder
* Kendinden önce yazılmış karakterin;
sıfır veya daha fazla tekrar etmesini ifade eder
+ Kendinden önce yazılmış karakterin;
bir veya daha fazla tekrar etmesini ifade eder
? Kendinden önce yazılmış karakterin;
olsa da olur olmasa da olurunu ifade eder
{123} Kendinden önce yazılmış karakterin;
parantez içerisine yazılan sayı kadar tekrar etmesini ifade eder
{1, 2} Kendinden önce yazılmış karakterin;
parantez içerisinde yazılan iki sayı arasında tekrar etmesini ifade eder
( … ) Parantez içerisine yazılan ifadeleri gruplamaya yarar
( … | … ) Parantez içerisine yazılan “|” dik tire işareti ya da anlamına gelir, içerisine yazılan ve dik tire ile ayrılan ifadelerden herhangi birisinin eşleşmesini ifade eder
[ … ] Köşeli parantez içerisine yazılan karakterlerden bir tanesini ifade eder
Kaçış karakteri. Yukarıda yazdığımız karakterleri normal olarak yazmak istediğimizde başına kaçış işaretini koyarız. Örneğin noktayı ifade etmek için .
D Rakam olmayan herhangi bir karakteri ifade eder
S Görünmez ve boşluk olmayan karakteri ifade eder
W Harf, rakam veya alt tire olmayan karakteri ifade eder
b Kelimenin başını veya sonunu ifade eder
[^ … ] Üç nokta yerine yazılan karakterler haricindeki karakterleri ifade eder
[a-z] A dan z’ye olan harflerden birisini ifade eder

Regex ayarları

Regex desenleri iki “/” (bölü) işaretinin arasına yazılır. Sondaki bölü işaretinden sonra isteğe bağlı olarak regex ayar karakterleri girilir.

Ayar karaktleri:

Karakter Açıklaması
i Büyük küçük harfe duyarsız olur
g İlk eşleşmede durmaz, kapsamlı tarama yapar
s Satır başı hariç her şeyi ifade eden nokta karakterinin satır başını da ifade etmesini sağlar
m ^ ve $ karakterlerinin her satırın başını ve sonunu ifade etmesini sağlar

Örnek kullanımı:

1
/elma/i

Bu örnekte büyük ELMA, küçük elma ya da ElMa şeklinde yazılanları da büyük küçük harfe aldırmadan yakalar.

Yukarıdaki örnek selma, elmas gibi kelimelerin içerisindeki “elma”ları da bulacaktır. Eğer sadece elma kelimesini aramak istiyorsak kelime başı ve sonunu ifade eden b kullanacağız.

1
/belmab/gi

Şimdi sadece elma kelimesini bulacağız, selma, elmas gibi diğer elma içeren kelimeleri yakalamayacaktır.

Sayıları yakalamak

Gelelim şimdi yukarıdaki tabloda listelediğimiz karakterlerin örnek kullanımına. Girilen içerikte sadece sayıları bulmak için “d” ve “+” karakterlerini kullanacağız.

1
/d+/g

Bu örnek sadece 1234321 789 sayılarla eşleşir. “g” ayarı ile de bir kere değil kapsamlı aramasını ifade ettik

Bir veya daha fazla tekrarı ifade eden “+” karakterinin başına herhangi bir rakamı ifade eden “d” yazdık. Daha işe yarar bir örnek için girilen içerikteki tarih formatında yazılmış ifadeyi yakalayalım.

1
/(d{2}.d{2}.d{4})/g

İfadenin karışık görünmesi sizi korkutmasın, ilgili yerlerden inceleyerek ayıkladığınızda ne olduğunu daha rahat özetleyebilirsiniz. d{2} 2 rakamı, sonrasında . kaçış karakteri ile noktayı, son kısımda ise 4 rakamı ifade ettik. Böylece 10.08.2013 gibi bir içerikle eşleşecektir.

Kelimeleri yakalamak

Yukarıdaki örnekle benzer bir ifade ile yapabiliriz.

1
/(w+)/g

w ifadesi herhangi bir harfi ifade ettiğini söylemiştik fakat Türkçe karakterlerin bu ifade için istisna olduğunu bilmeniz gerekiyor. Eğer Türkçe bir içerikle çalışıyorsak yapmamız gereken ifade şöyle olmalı;

1
/([a-zA-ZÇŞĞÜÖİçşğüöı]+)/g

Bu ifade ile Türkçe kelimeleri de yakalayabiliriz

Küçük ve büyük a’dan z’ye harlerin yanına Türkçe’de olan küçük ve büyük harfleri ekledik. Bir diğer örnek olarak da içerikten sadece istenilen bir kelimeyi almayı deneyelim.

1
/benim adım (w+)/gi

Merhabalar benim adım Musa!

Başlangıç ve sona göre yakalama

^ ve $ karakterleriyle başının ya da sonunun nasıl olacağını ifade edebiliriz. Örnek olarak sadece selam ile başlayan içeriği ayıklamayı deneyelim.

1
/^selam/

Bu örnek metin selam ile başlamadığı için hiç bir şeyle eşleşmeyecektir

selam! bu örnek daha samimi olduğu için eşleşecektir

Selam ile başlayan ve hoşçakal ile biten metnin arasında geçenleri yakalayacak bir örnek daha;

1
/^selam(.+)hoşçakal$/

selam buralar yakalanacak hoşçakal

Düzenli ifadeleri PHP ile kullanmak

Gelelim bu faydalı işlemleri PHP üzerinde kullanmaya. Bunun için bir kaç faydalı fonksiyon ile tanışacağız.

İfadenin eşleşip eşleşmediğini kontrol etmek

preg_match fonksiyonu ile yazdığımız ifadenin verdiğimiz içerikle eşleşmediğini kontrol edebiliyoruz. Örnekte girdinin geçerli bir saat formatı olup olmadığını kontrol edeceğiz.

1
2
3
4
5
6
7
8
9
10
11
$pattern= '/^([01][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]$/';
$content = '23:15:59';
if(preg_match($pattern, $content))
{
    echo 'Doğru bir saat girilmiş';
}
else
{
    echo 'Yanlış bir saat formatı girilmiş';
}

Eğer ifade metin içerisinde eşleşirse true aksi halde false döner.

Yazdığımız ifadenin açıklamasını da merak ediyorsanız;
Öncelikle ^ ile metnin başını ifade ettik, yani tam olarak bizim istediğimiz gibi başlamalı. Sonunda da $ kullandık, bu sayede tam olarak bizim istediğimiz başlangıca ve sona sahip olan bir içeriği aradığımızı ifade ettik.

Sonrasında ([01][0-9]|[2][0-3]) 2 ifadeyi gruplandırdık. Çünkü saat ya 01 den 19’a kadar ya da 20 dan 23’e kadar olabilir. Eğer [0-9]{2} şeklinde 0 ile 9 arasında 2 sayı ile eşleş deseydik, 99 gibi 23’den büyük sayılara da eşleşirdi.

Yakalanan içerikleri almak

Düzenli ifadelerde yakalamak ve ayırmak istediğimiz içeriklerin ifadelerini parantez içerisinde yazarız. Parantez içerisine yazılan ifadelere eşleşen içeriklere preg_match_all fonksiyonu sayesinde ulaşacağız. Bu fonksiyon tüm içeriği taramasını sağlayan “g” ayarını içerir, yani preg_match_all kullanırken “g” (global) ayarını yazmanıza gerek yok.

Teorik bilgi ve örneklerin haricinde biraz gerçek hayattaki kullanımlarına bakarak daha iyi kavrayabileceğimizi düşünüyorum. Bir sitenin kayak kodundan title etiketi arasında yer alan site başlığını yakalamak için şöyle bir ifade yazabiliriz.

1
2
3
4
5
6
$pattern = '/<title>(.+)</title>/i';
$content = file_get_contents('//www.phpr.org');
preg_match_all($pattern, $content, $results);
print_r($results);

Ekran çıktısı şöyle olacaktır;

1
2
3
4
5
6
7
8
9
10
11
12
Array
(
    [0] => Array
        (
            [0] => <title>php serüvenleri - PHP dersleri, PHP örnekleri, PHP kodları</title>
        )
    [1] => Array
        (
            [0] => php serüvenleri - PHP dersleri, PHP örnekleri, PHP kodları
        )
)

$results değişkenindeki dizinin ilk elemanı; girilen ifade ile eşleşen içeriklerin dizisini verir. Sonraki elemanları ise parantezler ile grupladığımız ifadelere eşleşen içeriklerin dizisini verir. Yani bizim asıl ihtiyacımız olan title etiketleri arasında parantez içerisine aldığımız karakterleri almak için 2. elemana bakacağız.

İkinci elemanda kendi içerisinde bir dizi, yani eğer birden fazla eşleşme olursa onları da sırayla verecektir.

Düzenli ifadeleri kullanarak içeriği değiştirme

Yine kullanışlı bir örnek ile açıklayalım. Girilen metin içerisine düz bir şekilde yazılan URL’leri HTML formatında link yapalım. Bunun için öncelikle bir URL’yi ifade edecek olan desen lazım. Ben internette hazır örneklerden birisini seçtim, dilerseniz siz de diğerlerine şuradaki adresten bakabilirsiniz. preg_replace fonksiyonu ile eşleşen ifadelerde yine parantez içinde grupladığımız ifadeleri istediğimiz şekilde değiştirebiliriz.

1
2
3
4
5
6
7
8
// URL'leri yakalayan desen
$pattern = '(https?://(([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,6}/?[^bs]+))';
$content = 'Diğer PHP serüvenlerine //www.phpr.org adresinden bakabilirsiniz';
$replace = '<a href="$0">$1</a>';
echo preg_replace($pattern, $replace, $content);

Ekranda düz yazı ile yazdığımız URL’nin link olmuş hali yazar;

Daha fazlası

İfade gruplarını yakalamamak

Yukarıda özellikle yakalamak istediğimiz ifadeleri parantez içine almamız gerektiğini söylemiştim. Fakat her parantez içine aldığımızı yakalamak istemeyebiliriz. Bunun için parantezleri (?: ... ) şeklinde kullanabiliriz.

Böylece bu parantezin yakaladığı içerik sadece çalışırken kullanılır, sonuçta gösterilmez.

1
/(w+@w+(?:.w+)+)/

E-mail adresini ifade eden desende iki grubumuz var, fakat içerideki grubu sonuçta almamıza gerek yok. İfadeyi çalıştırdığımızda sadece mail adreslerini veren bir dizimiz olacak.

İfade gruplarını isimlendirme

Yukarıdaki örnekte gereksiz parantezleri almayıp elde ettiğimiz sonucu biraz daha düzene sokmuş olduk. Şimdi ise bu gruba isim vererek daha da düzeni sağlayabiliriz.

Grupları /(?<grupismi>ifade)/ şeklinde isimlendirebilirsiniz.

1
2
3
4
5
6
$pattern = '/(?<email>w+@w+(?:.w+)+)/i';
$content = 'Bir kaç adres: elma@manav.com, yarimkilo@kasap.com, ates@askeriye.com';
preg_match_all($pattern, $content, $results);
print_r($results['email']);
1
2
3
4
5
6
Array
(
    [0] => elma@manav.com
    [1] => yarimkilo@kasap.com
    [2] => ates@askeriye.com
)

Hiç dizi elemanlarının hangisi benim ihtiyacım olandı diye uğraşmadan direkt isim verdiğimiz grubun yakaladığı içeriklere ulaşabiliriz.

Hava durumu

Yine pratik bir örnek ile meteoroloji sitesinden İstanbul için günlük hava durumunu yakalayan bir desen hazırlayalım. Bu tür işlerin püf noktası aradığımız içeriği çevreleyen eşsiz desenleri görmek.

İstanbul için günlük hava durumunu veren sayfa;
http://www.mgm.gov.tr/tahmin/il-ve-ilceler.aspx?m=ISTANBUL

Sayfanın kaynağını açıp aradığımız sıcaklığın hangi HTML etiketleri arasında olduğuna bakıyoruz.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Derece
preg_match_all('/<em class="renkMin zemimeZ">(.+)C</em></td>/si', $content, $results);
// İlk eşleşeni alıyoruz
$degree = $results[1][0];
// Hava durumunun ikonu ve açıklaması
preg_match_all('/"([wÇŞİĞÜÖöçşğüı ]+)" rowspan="2"><img src="..([w/.-]+)"/si', $content, $results);
$description = $results[1][0];
$image = 'http://www.mgm.gov.tr' . $results[2][0];
echo $degree . ' ' . $description;
echo '<img src="' . $image . '" />';

Ekranda hava durumunu görürüz.

Related Articles

Leave a Reply

Check Also

Close
Close

Reklam Engelleme

Please consider supporting us by disabling your ad blocker