· Št. online gostov: 1
· Št. online članov: 0
· Vseh članov: 712
· Najnovejši član: lega
|
|
Pameten moz je nekoc dejal "Zacetnik vidi problem in si rece: 'Oh to bom pa lahko z regexi naredil!', sedaj ima dva problema".
Ampak kljub temu so regexi zelo uporabni in resijo marsikateri drugace neresljiv problem ali pa vsaj kak problem mocno olajsajso, vendar pa je potrebno, ce se le da, iskati drugacno resitev, saj so regexi sami po sebi lahko izredno kompleksni in pocasni.
V tem clanku vam bom skusal predstaviti osnove regexov namigniti na to kako tezavno je dejansko spisati perfekten regex. Za zacetek naj povem kaj regex sploh je; regex je nekaksen napreden markup jezik za parsanje stringov, ki izhaja iz davnih casov racunalnistva, najbolj pa se je razvil pod okriljem perla. PHP podpira dve razlicni regex sintaksi, v tem clanku pa se bom omejil na perl kompatibilno, ker jo podpira veliko stevilo razlicnih jezikov in je v vecini primerov tudi hitrejsa.
V kombinaciji s perl kompatibilnimi regexi se v phpju uporabljajo funkcije:
- preg_grep, ki iz arraya vrne vse ujemajoce stringe
- preg_last_error, ki vrne zadnjo napako v regexu
- preg_match_all, ki vrne vse ujemajoce podstringe iz stringa
- preg_match, ki vrne prvi ujemajoci podstring
- preg_replace_callback, ki preko callback funkcije naredi substitucije v stringu
- preg_replace, ki zamenja ujemajoce podstringe z drugimi podstringi
- preg_split, ki razdeli string po ujemajocih podstringih
Najpogostejsa raba regexov v php je verjetno preverjanje, ce je nek string ustreznega formata, za kar uporabljamo funkcijo preg_match in primeren regex. Npr:
[koda]
if ( preg_match( '#^[a-z.]+@[a-z.]+$#i', $string ) )
{
// je e-mail
}else
{
// ni e-mail
}
?>[/koda]
Regex je bil v tem primeru #^[a-z.]+@[a-z.]+$#i,kar naj bi v grobem matchalo vse pravilne e-mail naslove (vendar jih ne, saj je to cela znanost in dejansko obstaja neka knjiga, kjer je opisana sestava pravega regexa za matchanje e-mailov). Oglejmo si ta preprost regex po vrsti:
- # oznacuje zacetek ali konec regexa
- ^ pomeni zacetek stringa, se pravi zahtevamo, da string matcha regex ze od vsega zacetka in ne sele nekje na sredini
- [a-z.] je character class, ki ga oznacujeta oglata oklepaja, in matcha katerikoli znak od a do z in piko
- + je kvantifikator, ki pomeni naj se, kar je pred njim, (se pravi [a-z.]) ponovi enkrat ali veckrat
- @ je staticen del stringa in matcha afno
- $ oznacuje konec stringa (tu se nahaja s podobnim namenom kot se je ^)
Ta regex bo za pravilne razumel vse maile, ki zgledajo nekako takole: janez.novak@gmail.com, ne bo pa matchal recimo janez.novak6@gmail.com. Pogosto uporabljan kvantifikator je tudi asterisk (*), ki matcha nic ali vec ponovitev, se pravi bi podobna koda:
[koda]
if ( preg_match( '#^[a-z.]*@[a-z.]*$#i', $string ) )
{
// je e-mail
}else
{
// ni e-mail
}
?>[/koda]
za pravilne oznacila vse stringe, ki vsebujejo afno.
Kaj pa ce hocemo za pravilne brati samo maile iz domene gmail.com in yahoo.com? Potem bi regex izgledal nekako takole:
[koda]
if ( preg_match( '#^[a-z]+@gmail.com$|^[a-z]+@yahoo.com$#i', $string ) ) ...
?>[/koda]
Znak | torej pomeni ali - podobno kot v normalni php kodi kjer v ta namen uporabljamo ||, da pa se izognemo nepotrebnemu pisanju lahko ta regex enakovredno napisemo takole:
[koda]
if ( preg_match( '#^[a-z]+@(gmail.com|yahoo.com)$#i', $string ) ) ...
?>[/koda]
kjer je vse v oklepajih t.i. subpattern oz. podregex. Opazili smo ze, da zgornji regex v e-mail naslovih ne dopusca stevilk, ki pa so dokaj pogoste, zato lahko uporabimo naslednji trik:
[koda]
if ( preg_match( '#^.+@(gmail.com|yahoo.com)$#i', $string ) ) ...
?>[/koda]
Tu smo character class zamenjali s piko, ki matcha katerikoli znak, se pravi ta regex res dopusca katerikoli e-mail z domen gmail.com in yahoo.com, verjetno je se celo prevec popoustljiv.
Vseskozi sem v primerih uporabljam tudi t.i. modifier #i. Modifierji spremenijo osnovno obnasanje regexa in jih napisemo za zakljucni znak regexa:
- i pomeni, da regex enako tretira tako majhne kot velike crke
- m regexu pove, da je string vecvrsticen, kar v osnovi pomeni samo, da ^ in $ ne oznacujeta zacetka/konca stringa, ampak zacetek/konec vsake vrstice
- s pomeni, da pika matcha tudi newline znake, ki jih drugace iz zgodovinskih razlogov ne
- x, ki omogoci ignoriranje vsega whitespace v regexu za lazjo berljivost
- ter se nekaj drugih, ki po mojem mnenju ne sodijo v clanek za zacetnike
Druga zelo pogosta raba regexov v php pa je razbiranje podatkov iz stringa, kar ponavadi pocnemo s preg_match_all. Tako bi lahko za branje vseh datumov iz nekega besedila uporabili nekaj takega:
[koda]
preg_match_all( '#([0-9]+)[^0-9]([0-9]+)[^0-9]([0-9]+)[^0-9]#', $besedilo, $matches );
?>[/koda]
kar bi napolnilo $matches array z vsemi podstringi iz stringa, tako da bi $matches[0], bil array vseh celih matchov, se pravi datumov, vsak naslednji index ($matches[1] do $matches[3]) pa bi bil array matchev vseh subpatternov iz oklepajev. Tako bi za datum 3/10/1928 dobili $matches array, ki bi zgledal nekako takole:
[koda]
array(
[0] => array(
[0] => '3/10/1928'
),
[1] => array(
[0] => '3'
),
[2] => array(
[0] => '10'
),
[3] => array(
[0] => '1928'
)
)
?>[/koda]
Za razdelilnik med deli datuma smo v tem primeru uporabili kar character class [^0-9], ki matcha vse kar ni stevilka (^ v tem primeru negira character class). Vendar pa smo se s tako sestavo regexa mocno usteli, ker iz razlicnih razlogov matcha marsikaj, kar v resnici ni datum, saj matcha vse serije treh stevil, razdeljenih s po enim nestevilskim znakom ... tudi za matchanje datumov bojda obstajajo cele knjige.
S tem clankom sem vam zelel predstaviti nekaksne osnove za vstop v svet regexov, vec pa si lahko preberete v php manualu, ce pa vam bo kdaj dolgcas pa lahko obiscete tudi moj blog. |
#1 |
na 12.08.2008 ob 00:35
#2 |
na 12.08.2008 ob 14:45
#3 |
na 23.10.2008 ob 10:54
#4 |
na 07.08.2010 ob 07:49
|
|
|
Za komentiranje se morate prijaviti.
|
|
|
|
Za pošiljanje sporočil morate biti prijavljeni.
|
|