Monday, June 4, 2012

PHP Regular Expression

Regular Expression atau Regex, merupakan sebuah teknik atau cara untuk mencari persamaan - presamaan atau mencari string yang di cocokan dengan string tertentu,dalam php yang paling banyak digunakan adalah PCRE atau (Perl Compatible Regular Expressions), penggunaan dari regex sebebenarnya cukup luas, secara umum digunkan untuk mencari string (kata, huruf, simbol) dalam kumpulan-kumpulan string, misalnya ada sebuah string "saya pergi sekolah", dalam string tersebut terdapat beberapa kata, dan kita ingin mencari beberapa kata dengan kondisi tertentu, misalnya mencari kata dengan awalan p, atau mencari kata dengan akhiran a atau mencari kata di antara kata saya dan kata sekolah, di sinilah regex berperan, untuk mencari string dalam string dengan patern (kondisi) tertentu.
Untuk lebih memahami mari kita mencoba implementasi regex, dengan membuats sebuah program sederahan
1
2
3
4
5
6
7
<?php
// buat  string
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// tulisakan hasil string
echo $string;
?>
Jika Program tersebut di jalankan tentu saja string yang tampil adalah string secara keseluruhan, karena kita tidak menerapkan fungsi regex di dalamnya, sekarang kita akan mencoba mencari string "abc" dalam string yang ada, secara simple nya kita akan mencoba mencari apakah string "abc" ada dalam kumpulan string dengan variabel $string
1
2
3
4
<?php
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
echo preg_match("/abc/", $string);
?>
Program di atas akan menghasilkan 1 (true), itu karena patern string yang kita gunakan (abc) ada dalam string sebelemunya, dengan menggunakan preg_match() hasil yang di dapatkan akan berupa 1 jika patern ditemukan atau sebaliknya akan manampilkan 0 jika patern tidak ditemukan, tetapi yang perlu di ingat adalah penggunaan preg_match() dalam sekala yang lebih besar tidaklah terlalu baik, penggunaan strpos() atau strstr() akan jauh lebih baik dibandingkan dengan preg_match(), tetapi disini kita akan menggunakan preg_match(), karena ini juga contoh yang sederhana :)

Mecocokan Awalan dari String

Disini kita akan mencoba mencari string yang awalan dari string tersebut kita tentukan dalam patern kita, misalnya mencari string yang berawalan P, atau mencari string yang berawalan m dan lainya, dalam regex kita akan menggunkan simbol ^ sebagai penanda bahwa kita mencari kecocokan awalan dari string yang kita berikan,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
// string
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// mencoba mencocokan awalan dari string
if(preg_match("/^abc/", $string))
{
    //jika awalan ditemukan
    echo 'String dimulai dengan abc';
    }
    else
    {
    //jika awalan tidak ditemukan
    echo 'string tidak di awali dengan abc';
}
?>
Jika kita menjalankan program di atas, kita akan mendapatkan pesan String dimulai dengan abc, tanda / dan \ merupakan delimeter (cakupan) dari regex yang kita berikan, sedangkan simbol ^ mencocokan awalan dari string tanpa memperdulikan string setelahnya

case insensitive

Jika kita menggunakan code di atas untuk mencari string dengan awaln ABC dengan patern seperti if (preg_match("/^ABC/", $string)) hasinya string tidak di awali dengan abc, karena memang tidak ada string yang di awali dengan ABC, walapun pada hakikatnya abc = ABC, tetapi dalam programming kadang itu bisa menjadi sesuatu yang berbeda, untuk itu kita harus memberi tau kan kepada regex kita bahwa hal itu tidaklah berbeda, dengan cara menambahkan huruf i di akhir delimeter patern yang kita berikan, dengan begitu regex tidak akan memperdulikan huruf kecil dan huruf besar, atau kita akan mencari awalan string tanpa memperdulikan huruf besar atau tidak, seperti ABC, AbC, abc, ABc dll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
// string
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// mencoba mencocokan awalan dari string
if(preg_match("/^ABC/i", $string))
{
    //jika awalan ditemukan
    echo 'String dimulai dengan abc';
    }
    else
    {
    //jika awalan tidak ditemukan
    echo 'string tidak di awali dengan abc';
}
?>

Mecocokan Akhiran dari String

Jika tadi kita sudah membahas cara sederhana untuk mencari kecocokan string di awalan string, sekarang kita akan mencoba mencari kecocokan di akhiran string, caranya tidak jauh berbeda dengan cara sebelumunya, kita tetap meggunakan simbol ^ sebagai patern regex, hanya bedanya simbol ^ kita berikan di awal patern regex dan menambahkan patern \z di akhir, misalnya kita mencari string yang berakhiran 89 maka patern yang kita berikan adalah preg_match("/89\z/i", $string), tetapi dalam implentasinya banyak yang melakukan kesalahan dalam menerapakan regex yang mencari kecocokan di akhiran string dengan menggunkan simbol $, sebenarnya itu salah, seharusnya kita menggunkan patern \z untuk mencari kecocokan di akhiran string, karena jika menggunakan simbol $ saja hasilnya akan selalu true (1) jika memang patern ditemukan, tetapi masalahnya bagaimana jika masih ada baris selanjutnya ? , tentu saja hasilnya tidak akan sesuai dengan harapn kita, untuk itulah simbol patern $ tidak diperlukan.kecuali jika memang kita mencari akhiran dalam string mempunyai banyak baris., seperti contoh berikut
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
//string
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
if(preg_match("/89\z/i", $string))
{
    echo 'String dikahiri dengan 89';
    }
    else
    {
    echo 'String tidak diakhiri dengan 89';
}
?>
Dan jika string yang kita gunakan mempunyai baris-baris lainya kitaa seharunya menggunakan regex seperti berikut
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
//string
$string = 'abcdefghijklmnopqrstuv
wxyz0123456789';
if(preg_match("/^89$/i", $string))
{
    echo 'String dikahiri dengan 89';
    }
    else
    {
    echo 'String tidak diakhiri dengan 89';
}
?>
Perbedaanya cukup jelas kan, penggunaan patern preg_match("/89\z/i", $string) dengan patern preg_match("/^89$/",$string), patern - patern tersebut menunjukan perbedaan string yang mempunyai baris dengan string yang tidak mempunyai baris, penggunaan seperti inilah yang perlu di perhatikan, jika tidak kita pasti beranggapan bahwa patern kita salah atau sebaliknya :)

Meta characters

Di awal kita sudah mengenal beberapa simbol yang kita gunakan dalam regex, seperti simbol ^ yang menunjukan awal dari string, dam simbol $ dan \z yang menunjukan akhir dari string, masing-masing dari simbol tersebut mempunyai fungsi dan arti tersendiri dalam regex,tetapi dalam regex masih banyak simbol - simbol lainya yang juga memiliki arti dan fungsi tersendiri, seperti berikut
  • . (full stop)
  • ^ (Caret)
  • * (Asterix)
  • + (Plus)
  • ? (Question Mark)
  • { (Opening Curly brace)
  • } (Closing Curly brace)
  • [ (Opening Brace)
  • ] (Closing Brace)
  • \ (Back Slah)
  • | (Pipe)
  • ( (Opening Parens)
  • ( (Closing Parens)
Kita akan mencoba membahas satu persatu dalam tutorial ini, yang paling adalah kita mengerti apa mereka (simbol tersebut), misalnya penggunaan \ (Black slah) digunakan ketika kita akan meng-escape karakter terntentu seperti < atau > atau + atau karakter yang termasuk dalam meta characters di atas, misalnya kita akan mengescape karakter dalam string 1+1, kita akan mencari karakter dengan awalan 1+1 dalam string tertentu
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
//string
$string = '1+1=2';
if(preg_match("/^1\+1/i", $string))
{
    echo 'String diawali dengan 1+1';
    }
    else
    {
    echo 'String tidak diawali dengan 1+1';
}
?>
Jika program tersebut di jalankan, kita akan mendapatkan hasil String diawali dengan 1+1, karena patern 1+1 ditemukan dalam string fungsi \ (back slah) diatas akan membiarkan tanda + sebagai tanda +, bukan sebagai meta characters,dan jika kita tidak memberikan simbol \ maka hasilnya akan String tidak diawali dengan 1+1, akrena patern tidak cocok, regex meng-anggap bahwa tanda + merupakan meta characters, jika dalam percobaan teman-teman menemukan string yang menggunakan \ maka simbol \ harus di escape terlebih dahulu dengan memberikan simbol \ double (\\) sehingga simbol \ dalam string akan di anggap sebagai patern bukan sebagai meta characters.

Meta characters in Actions

Saya harap sampai disini teman-teman masih belum bosan :D, jika di awal kita telah membahas simbol ^, $ dan \ maka sekarang kita mencoba membahas sedikit tentang meta characters yang lainnya, seperti misalnya penggunaan simbol [ dan ], beberapa waktu lalu sempat seorang teman bertanya kepada saya masalah perbedaan tanda tersebut dengan simbol (), mudah-mudahan tutorial ini bisa menjawabnya
simbol [ dan ] digunakan untuk memberitahukan kepada regex bahwa kita menggunakan patern yang lebih spesipik, misalnya hanya [aiueo] saja, atau [a-z] saja, atau [0-9] saja dan aptern yang lainya, tanda - menunjukan range (sampai) dalam kondisi tertentu seperti a sampai z atau 0 sampai 9, seperti contoh berikut
1
2
3
4
5
<?php
// string
$string = 'big';
echo preg_match("/b[aiueo]g/", $string, $matches);
?>
Jika kita jalankan program di atas akan menghasilkan true(1), karena preg_match() menemukan patern yang kita berikan (cocok), kenapa ? karena pada regex diatas kita memberikan patern preg_match("/b[aiueo]g/",$string) yang artinya kita mencari kata "b?g" dan huruf di antara b dan g bisa berbentuk "aiueo"m jadi misalnya dalam string terdapat kata big maka hasilnya akan true karena i terdapat dalam patern kita, dan jika seandainya dalam string terdapat kata bug, maka nulinya akan tetap true(1), karena u ada dalam patern yang kita berikan, simple bukan ? yang perlu di ingat adalah meta characters tidak akan bekerja jika kita masukan dapal regex [ dan ], misalnya preg_match("/b[^1\+1]g/", $string),jadi penggunaan simbol [ dan ] hanya untuk mencari kecocokan dalam ruang lingkup tertentu saja
Dan bagaiaman jika kita ingin mencari string yang cocok tetapi didalamnya terdapat salah satu meta characters di atas ? atau mencari string yang cocok dalam range tertentu, memang benar, penggunaan meta characters dalam simbol [ dan ] tidak diperbolehkan, tetapi kadang - kadang boleh :D, tetapi dengan kondisi tertentu, misalnya kita ingin mencari string yang tidak di awali dengan string b dalam string, ingat TIDAK di awali, bukan di AWALI, berikut contohnya
1
2
3
4
5
6
7
8
9
10
<?php
$string = 'abcefghijklmnopqrstuvwxyz0123456789';
preg_match("/[^b]/", $string, $matches);
foreach($matches as $key=>$value)
    {
    echo $key.' -> '.$value;
    }
?>
Jika program di atas di jalankan kan, kita akan mendapatkan hasil 0->a, karena hanya dua string tersebut yang tidak di awali dengan string b, masih bingung ya ?, jika kita kembali ke awal, penggunaan simbol [ dan ] menunjukan penggunaan yang lebih spesipik, string [a-z] dan [0-9], dalam string yang kita berikan terdapat dua cakupan, maka regex meng-anggap bahwa itu dua range yang berbeda, itulah penyebabnya kenapa kita mendapatkan hasil 0->a, sekarang sudah mengertikan ?
Sekarang mari kita merubah sedikit program kita, jika pada awalnya kita menggunakan fungsi preg_match(), sekarang kita akan mencoba menggunakan fungsi preg_match_all() dalam mencari string yang TIDAK DIAWALI dengan string b dengan patern preg_match_all("/[^b]/",$string,$matches)
1
2
3
4
5
6
7
8
9
10
<?php
$string = 'abcefghijklmnopqrstuvwxyz0123456789';
preg_match_all("/[^b]/", $string, $matches);
foreach($matches as $key=>$value)
    {
    echo $value;
    }
?>
Jika program tersebut kita jalankan hasilnya adalah acefghijklmnopqrstuvwxyz0123456789, coba perhatikan hasilnya, tidak ada string b kan ? , ini karena kita mencari semua karakter yang tidak sama dengan string b /[^b]/, berbeda dengan penggunaan preg_match(), preg_match_all() lebih kepada hasil yang menunjukan kecocokan pada string, nah dengan demikian kita bisa menarik keluar string terntentu dari string tersebut, misalnya kita ingin mencari string yang tidak sama dengan huruf dari 0 -9 dari string tersebut, dengan menggunakan preg_match_all() kita bisa melakukannya, seperti contoh
1
2
3
4
5
6
7
8
9
10
<?php
$string = 'abcefghijklmnopqrstuvwxyz0123456789';
preg_match_all("/[^0-9]/", $string, $matches);
foreach($matches as $key=>$value)
    {
    echo $value;
    }
?>
hasil dari program tersebut adalah abcefghijklmnopqrstuvwxyz, sekarang sudah mengerti kan penggunaan preg_match() dan preg_match_all() ? dan kita bisa melihat tanda ^ dalam simbol [ dan ], di sini kita bisa menyimpulkan bahwa simbol ^ jika berada dalam simbol [ dan ] bukan berarti awalan atau akhiran, tetapi menunjukan kondisi NOT atau TIDAK.

Lebih jauh tentang Escaping Character

Disini kita akan lebih kapada bagaimana memanfaatkan simbol \ dalam meng-escape karakter terentu, meng-sacape bisa di artikan sabagai membaypass, atau melewati sehingga karekter teresbut bisa di proses.misalnya kita akan mencari string yang berada dalam simbol [ dan ], contohnya seperti berikut
1
2
3
4
5
6
7
8
<?php
$string = 'ini adalah [stringsaya]';
preg_match_all("/[\[\]]/", $string, $matches);
foreach($matches[0] as $value)
{
    echo $value;
}
?>
Jika kita menjalankan program di atas maka hasilnya akan kosong atau hanya [], karena kita hanya memberikan patern untuk string yang cocok dengan simbol [ dan ], jika kita perhatikan patern tersebut tanpa menggunakan simbol black slah \ maka bentuknya akan seperti /[[]]/, dan jika kita hanya mencari dan megambil string yang berada di antara apitan simbol [ dan ] kita harus memberikan meta characters yang berbeda, yang menunjukan string apapun yang berada di antara simbol [ dan ], dengan catatan kita tidak menggunakan simbol [ dan ] sebagai regex, seperti contoh
1
2
3
4
5
<?php
$string = 'ini adalah [stringsaya]';
preg_match_all("/\[.*\]/", $string, $matches);
print_r($matches);
?>
Jika Program tersebut di jalankan akan menampilkan [stringsaya] dalam susun array, dan bandingkan regex yang ada dengan regex sebelumnya, pasti teman-teman bisa memahami maksudnya
sekarang kita mencoba meta characters . (full stop), simbol ini akan mencocokan semua string kecuali di pisahkan oleh bari baru seperti \n atau \r, dan jika kita ingin mencari semua string yang tidak memperdulikan baris baru seperti pemisahan \r dan \n kita cukup menambahkan flag \s di akhir delimeter regex yang kita berikan, seperti contoh
1
2
3
4
<?php
$string = 'sex at noon taxes';
echo preg_match("/s.x/", $string, $matches);
?>
Jika program di jalankan, hasilnya akan true (1), karena preg_match() menemukan 1 patern yang cocok, arti regex tersebut dapat di artikan seperti halnya kita menccari string di antara string s dan x tetapi hanya satu karakter saja, tidak perduli karakter itu berbentuk apa, misalnya sex, six, sox, s0x,s3x, daln lainya, jika karakternya berbentuk seix atau seex maka hasilnya akan 0 atau preg_match() tidak menemukan 1 patern yang cocok
Sekarang mari kita coba untuk string yang memiiki baris yang dipisahkan oleh \r atau \n, seperti contoh
1
2
3
4
5
<?php
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
echo nl2br($string);
echo preg_match_all("/\s/", $string, $matches);
?>
jika program di jalankan hasilnya akan menunjukan string yang cocok dengan patern dan di pisahkan oleh pindah baris seperti \r dan \n, dan pada akhir akan tampil angka 4 yang menunjukan jumlah dari pindah baris yang ada karena kita menggunakan preg_match_all().
meta characters selajutnya adalah simbol *, simbol * digunakan untuk mencocokan string apa saja seperti penggunaan .*, simbol * akan meng-anggap cocok setiap string yang ada sebelum mapun sesudah dari patern yang kita berikan, bingung ya, let take it in action
1
2
3
4
<?php
$string = 'php';
echo preg_match("/ph*p/", $string, $matches);
?>
Hasil dari script di atas akan menghasilkan nilai 1, karena kita mencari kecocokan ada tidaknya string sesudah string h dari patern yang kita berikan, ada dan tidaknya string setelah string h tidak menjadi masalah, karena simbol * akan menghasilkan nilai satu, jika string berbentuk pp atau phhhhp maka hasilnya akan tetap 1, intinya kita mencari string yang cocok dengan p????p ? merupakan pengganti dari simbol *, jadi ada tidaknya string sesudah maupun sebelum string h akan di anggap ada karena kita menggunakan meta characters *
berbeda dengan simbol +, jika simbol * mencocokan semaunya, simbol + merupakan kebalikanya, jika menggunakan simbol * string pp dinaggap memiliki kecocokan maka jika kita menggunakan simbol + maka string pp tidak memiliki kecocokan dengan patern yang kita berikan, lihat contoh
1
2
3
4
<?php
$string = 'pp';
echo preg_match("/ph+p/", $string, $matches);
?>
Hasilnya akan 0, karena simbol + tidak meng-anggap ada patern yang cocok, Berbeda juga dengan simbol ?, penggunaan simbol ? hampir sama dengan simbol + dan *, hanya saja simbol ? digunakan untuk optional regex, seperti .*? yang mengartikan semuanya,
Yang paling sering digunakan dalam regex sebenarnya adalah simbol { dan }, karena dengan menggunakan simbol ini regex menjadi lebih ampuh dalam mencocokan patern dengan string, misalnya kita ingin mencari string numeric dalam sebuah string yang jumlahnya sebanyak 3 digit saja, seperti contoh
1
2
3
4
<?php
$string = 'PHP123';
echo preg_match("/PHP[0-9]{3}/", $string, $matches);
?>
Dalam regex tersebut kita memberikan patern untuk mencari dan mencocokan string dengan patern yang ita berikan, singkatnya kita mencari angka dalam string yang jumlah digitnya 3 (tiga), patern [0-9] menunjukan kalo kita mencari jenis numeric sedangkan {3} menujukan kalo kita mencari yang jumlah digitnya sebanyak 3 digit

Special Sequences

Sequences merupakan pradefined dalam class yang kita gunakan, digunakan untuk menggantikan beberapa regex yang panjang sehingga menjadi lebih singkat, Sequences di lambangkan dengan huruf dan di letakan di belakang delimeter regex, berikut beberapa jenis dan fungsinya
  • \d digunakan untuk mencocokan semua jenis angka, sama dengan [0-9]
  • \D digunakan untuk mencocokan semua jenis yang bukan angka sama dengan [^0-9]
  • \s digunakan untuk mencocokan semua whitespaces, sama dengan [\t\n\r\f\v]
  • \S digunakan untuk mencocokan semua non whitespaces, sama dengan [^\t\n\r\f\v]
  • \w digunakan untuk Alphanumeric sama dengan [a-zA-Z0-9]
  • \W digunakan untuk non-Alphanumeric, sama dengan [^a-zA-Z0-9]
Jika kita implementasikan kedalam program, misalnya untuk mencari semua string yang hanya berupa alpha numeric, kita dapat menggunakan preg_match_all() dan Sequences \w, seperti contoh
1
2
3
4
5
6
7
8
<?php
$string = 'ab-ce*fg@ hi & jkl(mnopqr)stu+vw?x yz0>1234<567890';
preg_match_all("/[\w]/", $string, $matches);
foreach($matches[0] as $value)
{
    echo $value;
}
?>
Jika kita jalankan, maka semua karakter yang termasuk dalam Alphanumeric akan tampil, karena kita memberikan Sequences \w dalam regex, berbeda jika kita memberikan Sequences \W maka yang tampil adalah semua karakter yang bukan Alphanumeric, untuk penggunaan Sequences yang lain juga sama, tergntung fungsinya saja

Capturing Text Inside HTML Tags

skerang kita akan mencoba menggunakan regex dalam html, kita akan mencoba mengambil beberapa string berdasarkan tag html, untuk penjelsan dari masing-masing regex saya rasa sudah cukup jelas dari awal sampai akhir, di bagian ini kita akan mencoba menggabungkannya menjadi satu
1
2
3
4
5
6
7
<?php
$html = file_get_contents('http://www.contoh.org/example.html');
preg_match_all('@<h([1-6])>(.+?)</h\1>@is', $html, $matches);
foreach ($matches[2] as $text) {
    print "Heading: $text \n";
}
?>
Program di atas jika di jalankan akang menampilkan semua string yang berada dalam tag h1 sampai h6, untuk hasilnya teman-teman bisa mencobanya dengan mengcapture subuah halaman web dan melihat hasilnya
1
2
3
4
5
6
7
<?php
$html = file_get_contents('http://www.contoh.org/example.html');
preg_match_all('@<(strong|em)>(.+?)</\1>@is', $html, $matches);
foreach ($matches[2] as $text) {
    print "Text: $text \n";
}
?>
Program di atas akan menampilkan semua string yang mempunyai attribut seperti strong, atau em, teman-teman bisa menambahkan regex yang lain, seperti i untuk italic, atau b untuk bold
1
2
3
4
5
6
7
8
9
<?php
$html = '<link rel="icon" href="http://www.example.com/icon.gif"/>
<link rel="prev" href="http://www.example.com/prev.xml"/>
<link rel="next" href="http://www.example.com/next.xml"/>';
preg_match_all('/rel="(prev|next)" href="([^"]*?)"/', $html, $bothMatches);
preg_match_all('/rel="(?:prev|next)" href="([^"]*?)"/', $html, $linkMatches);
print '$bothMatches is: '; var_dump($bothMatches);
print '$linkMatches is: '; var_dump($linkMatches);
?>
1
2
3
4
5
6
7
<?php
$html = '<link rel="icon" href="http://www.example.com/icon.gif"/>
<link rel="prev" title="Previous" href="http://www.example.com/prev.xml"/>
<link rel="next" href="http://www.example.com/next.xml"/>';
preg_match_all('/rel="(?:prev|next)"(?: title="[^"]+?")? href="([^"]*?)"/', $html, $linkMatches);
print '$bothMatches is: '; var_dump($linkMatches);
?>

1 comment:

  1. kalau membuat inisialisasi huruf konsonan atau vokal dengan bagaimana?
    misalnya inputan “saya makan”
    hasilnya
    1. saya = kvkv
    2. makan = kvkvk
    ket:
    k = konsonan
    v = vokal
    terimakasi

    ReplyDelete