Menu

Regex in PHP

1. Ce este regex-ul?

Regex-ul sau expresiile regulate sunt in general un string cu reguli pentru potrivirea cu un sir(string). Regex-ul este folosit in general pentru a cauta potriviri intr-un sir si a returna daca a fost gasit iar dupa caz a schimba acea parte.

2. Introducere

Inainte de a porni la drum si a explica si putina teorie doresc sa ma asigur sa ca ati inteles ce face acest regex. De exemplu in ipostaza de a cauta, regex-ul (php|asp) poate reprezenta cuvintele php si asp. Daca am dorii sa reprezentam cuvantul casa si masa am folosii (c|m)asa. Operatorul regex | reprezinta operatorul boolean OR iar regex-ul (c|m)asa ar suna in cuvinte: oricare dintre c si m iar dupa urmeaza asa. Daca dorim sa scriem un regex care sa specifice 3 numere am folosii [0-9]{1,3}.

3. Structura regex in PHP

O expresie regulata este de forma si obligatoriu in ordinea urmatoare:
  • delimitator
  • reguli
  • delimitator
  • modificatori
  1. Delimitatorul - este cel care separa regulile de modificatori, cel care specifica ca acolo este o expresie regulata. Delimitatorul recomandat in PHP este caracterul /(slash). El este de asemenea recomandat si in alte limbaje precum JavaScript. Primul delimitator trebuie sa fie obligatoriu acelasi cu al doilea.
  2. Regulile - sunt cele exemplificate si in capitolul Introducere al acestui articol. Regulile sunt scrise cu ajutorul operatorilor regex(caractere speciale regex sau altfel spus meta caracterele) si caracterelor simple.
  3. Modificatori - sunt care modifica modul cum este inteles regex-ul de PHP, de exemplu modificatorul i spune ca regex-ul sa se faca in mod case insensitive - sa nu exista diferenta intre literele mici si literele mari

4. Operatori regex

Operatorilor regex li se mai spune si meta caractere. Noi vom folosii prima varianta si anume operatori regex. In tabelul de mai jos veti vedea atat operatori regex cat si clase de caractere(folosite pentru scrie codul mai rapid).
Operator Descriere
^ Specifica inceputul unui sir. Atentie: Cand este primul caracter dintre paranteze patrate([ si ]) semnifica negatia similar cu operatorul boolean !.
$ Specifica sfarsitul unui sir
[] Specifica oricare caracter din parantezele patrate sau oricare caracter reprezentat de regulile din panatezele patrate
() Specifica o grupare de reguli. Parantezele sunt folosite pentru a prelua doar parti dintr-un string sau a specifica o lista de optiuni a regulilor.
- O enumerare consecutiva de caractere, se pot folosii atat numere(exemplu: 0-9 care reprezinta 0123456789) cat si litere(exmplu: A-B care reprezinta toate literele de la A pana la B)
. Oricare caracter inafara de \n (CRLF aka linie noua) in caz ca nu este precizat si modificatorul(cel dupa delimitator) s
{n} Expresia precedenta acestui operator se repeta de n ori
{x,y} Expresia precedenta acestui operator se poate repeta de la x la y ori
* Expresia precedenta acestui operator se repeta de la 0 la un infinit de ori. Operatorul * este similar cu {0,}
+ Expresia precedenta acestui operator se repeta de la 1 la un infinit de ori. Operatorul + este similar cu {1,}
? Expresia precedenta se repeta de 0 sau o singura data. Operatorul ? este similar cu {0,1}
| Operatorul boolean Or, este folosit intre paranteze simple cand se specifica o lista de optiuni.
Transforma operatorul de dupa el intr-un simplu caracter.
d Specifica un caracter numeric, un numar. Operatorul special d este similar cu [0-9]
D Specifica un caracter non-numeric, orice alt caracter inafara de un numar. Operatorul special d este similar cu [^0-9]
w Reprezinta un caracter alphanumeric. Operatorul special d este similar cu [a-zA-Z0-9_]
W Reprezinta un caracter non-alphanumeric. Operatorul special D este similar cu [^a-zA-Z0-9_]
s Reprezinta un caracter whitespace. Operatorul special s este similar cu [ \n fv]
S Reprezinta un caracter non-whitespace. Operatorul special s este similar cu [^ \n fv]
[:alnum:] Reprezinta un caracter alfanumeric. Similar cu w si [A-Za-z0-9]
[:alpha:] Reprezinta caracterele alfabetice. Similar cu [A-Za-z]
[:blank:] Reprezinta space sau tab. Similar cu [ ]
[:digit:] Reprezinta un numar. Similar cu [0-9]
[:punct:] Reprezinta caracterele pentru punctuatie. Similar cu [][!"#$%&'()*+,./:;<=>?@^_`{|}~-]
[:space:] Reprezinta un caracter whitespace. Similar cu s sau [ \n fv]
[:upper:] Reprezinta majusculele. Similar cu [A-Z]
[:lower:] Reprezinta minusculele. Similar cu [a-z]
[:xdigit:] "Numere" hexadecimale(de exemplu codurile pentru culori CSS #FFFFFF). Similar cu [A-Fa-f0-9].

5. Regex si preg_match

int preg_match ( string $pattern , string $subiect [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
Functia preg_match este folosita pentru a testa daca o expresie regulata se potriveste cu un string. Ea returneaza 1 in caz ca patternul(expresia regulata) se potriveste cu subiect-ul(stringul).

5.1 Exemplu simplu de utilizare

Pentru inceput voi exmplifica folosirea unui regex extrem de simplu pentru a arata modul simplu de folosirea a functiei preg_match. Retineti sa folositi regex doar acolo unde este nevoie , functia strpos este mult mai rapida ca preg_match. Functia preg_match este folosita in general(dar fara a se limita la):
  • Verificare daca o adresa e-mail este valida
  • Verificare daca o parola este sigura
  • Verificare daca un username contine caractere valide
  • Verificare daca un numar de telefon este valid
<?php  
$string = 'Acesta este un string.';
if(preg_match('/este/', $string)){
	echo 'Cuvantul <b>este</b> a fost gasit in stringul dat.';
} else{
	echo 'Cuvantul <b>este</b> nu a fost gasit in stringul dat.';
}
?>
Output:

5.2 Verificare daca stringul contine numere

<?php 
$string = 'Acest string contine 1 numar.';
$regex 	= '/[0-9]/';
if(preg_match($regex, $string)){
	echo 'Acest string contine numere.';
} else{
	echo 'Acest string nu contine numere.';
}
?>
Output:

Iar daca modifcam string-ul ca sa nu mai contina numere:
<?php 
$string = 'Programarea este interesanta.';
$regex 	= '/[0-9]/';
if(preg_match($regex, $string)){
	echo 'Acest string contine numere.';
} else{
	echo 'Acest string nu contine numere.';
}
?>
Output:

5.3 Folosire operatori ca simple caractere

Dupa cum am spus la capitolul despre operatori folosim caracterul pentru a transforma operatorul de dupa intr-un simplu caracter.
Mai jos vei vedea un exemplu de cod gresit in care incercam sa cautam textul a(b) dar fara a transforma parantezele in simple caractere:
<?php 
# ACESTA ESTE UN EXEMPLU DE COD GRESIT
# Rolul lui este doar sa demonstreze cum sa NU faceti
$string = ' Text care contine expresia a(b)';
# Observati ca parantezele din regex sunt gresite deoarece sunt luate ca operatori 
# si nu ca simple caractere
if(preg_match('/a(b)/', $string)){
	echo 'Expresia <b>a(b)</b> a fost gasita in stringul dat.';
} else{
	echo 'Expresia <b>a(b)</b> nu a fost gasita.';
}
?>
Output:

Dupa cum vedeti nu ne-a dat rezultatul corect cu toate ca textul contine a(b) dar parantezele sunt operatori si nu pot fi folositi ca caractere fara a se pune inaintea lor operatorul
Insa daca transformam parantezele in simple caractere folosind operatorul
<?php 
# ACESTA ESTE UN EXEMPLU DE COD GRESIT
# Rolul lui este doar sa demonstreze cum sa NU faceti
$string = ' Text care contine expresia a(b)';
# Observati ca parantezele din regex sunt gresite deoarece sunt luate ca operatori 
# si nu ca simple caractere
if(preg_match('/a(b)/', $string)){
	echo 'Expresia <b>a(b)</b> a fost gasita in stringul dat.';
} else{
	echo 'Expresia <b>a(b)</b> nu a fost gasita.';
}
?>
Output:

Dupa cum observati acum rezultatul este cel corect din cauza ca am transofrmat parantezele in simple caractere din operatori folosind operatorul

5.4 Verificare adresa de e-mail

Cand utilizatorul ne furnizeaza o adresa de e-mail trebuie sa stim cel putin daca ea este valida, pentru asta noi folosim functia preg_match. Exemplu:
<?php  
	if(isset($_GET['email'])):
		$adresaEmail = trim(htmlentities($_GET['email'], ENT_QUOTES));
		# Folosim caracterul  in fata caracterului - pentru a putea folosii caracterul - fara a reprezenta un operator
		$pattern = '/^[a-zA-Z0-9_-]{3,30}@[a-zA-Z0-9-]{3,30}.[a-zA-Z]{1,4}$/';
		if(preg_match($pattern, $adresaEmail)){
			echo 'Adresa de e-mail este corecta.';
		} else{
			echo 'Adresa de e-mail nu este corecta.';
		}
		echo '<hr/><a href="?">Doresc sa testez din nou.</a>';
	else:
		echo '<form>';
			echo '<input type="text" name="email" placeholder="Introdu o adresa de e-mail"/>';
			echo '<input type="submit" value="Verifica daca este valida"/>';
		echo '</form>';
	endif;
?>
Poti testa acest cod in iframe-ul de mai jos:

6. Preg Replace

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
  • $pattern - reprezinta regex-ul folosit pentru cautarea textului ce trebuie modificat
  • $replacement - reprezinta textul cu care va fi inlocuit. Sunt permise variabilele $n unde n este numarul parantezei.
  • $subject - stringul in care se vor face modificarile
  • $limit - cate modificari sa faca maxim
  • $count - Incepand de la PHP 5.1.0 aceasta variabila reprezinta numarul de modificari facute, este atribuita prin referinta in functie.
Functia preg_replace returneaza un array in caz ca $subject este array sau un string in caz ca $subject este un string. Daca apare o eroare returneaza NULL.

6.1 Exemplu stergere caractere non-alfaumerice

Se intampla foarte des sa avem nevoie doar unele caractere dintr-un string. Exemplu stergere caractere non-alfaumerice:
<?php  
$string = 'A$ce%st t!#ex#t#! co^&nti!n#e c#a(r)a&c%te[r;]e n)/ep/e/r|mi~s`e.';
$pattern = '/[^ a-zA-Z0-9.-\_]/';
echo preg_replace($pattern, '', $string);
?>
Output:

7. Modificatori

Modificatorii PHP sunt i, U, s, m, x, e, S dar noi in acest capitol vom vorbii doar despre 2: i si s.

7.1 Modificatorul i

Modifcatorul i este folosit pentru a face cautarea insensbila la majuscule, nu vor conta tipuri literelor(minuscule sau majuscule).
Mai jos veti vedea un exemplu in care cautam text cu ajutorul regex si cu ajutorul modificatorului i il facem sa nu tina cont de majuscule.
<?php 
$string = 'TeXTul AcEsTa eStE fOaRte INCURCAT!';
if(preg_match('/acesta/i', $string)){
	echo 'Regex-ul s-a potrivit cu stringul dat.';
} else{
	echo 'Regex-ul <b>nu</b> s-a potrivit cu stringul dat.';
}
?>
Output:


Mai jos o sa vezi acelasi exemplu dar in care nu folosim modifcatorul i si astfel regex-ul nu se va mai potrivii cu stringul dat.
<?php 
$string = 'TeXTul AcEsTa eStE fOaRte INCURCAT!';
if(preg_match('/acesta/', $string)){
	echo 'Regex-ul s-a potrivit cu stringul dat.';
} else{
	echo 'Regex-ul <b>nu</b> s-a potrivit cu stringul dat.';
}
?>

Dupa cum ati observat nu s-a potrivit deoarece regex-ul default tine cont de majuscule daca nu este specificat modificatorul i.

7.2 Modificatorul s

Dupa cum probabil ati observat cand dorim sa reprezentam o variabila cu orice caractere folosim (.*?) dar atat timp cat modificatorul s nu este specificat ea nu reprezinta si linia noua. Modificatorul s include si liinile noi in expresia noastra regulata.
Mai jos aveti un exemplu in care nu folosim modificatorul s:
<?php 
$string = "de aici primul &#92;n al doilea pana aici";
# Folosim nl2br pentru a transforma liniile(&#92;n) in <br/>
# Folosim $n pentru a reprezenta valoarea unei grupe reprezentate de paranteze
if(preg_match('/de aici(.*?)pana aici/', $string )){
	echo 'Expresia regulata corespunde cu stringul.';
} else{
	echo 'Expresia regulata <b>nu</b> corespunde cu stringul.';
}
?>
Output:

Dupa cum observati cu toate ca noi am precizat sa caute de aici(.*?)pana aici care daca ne uitam in string exista problema este ca nu sunt incluse si liniile noi. Uitati si daca folosim modificatorul s:
<?php 
$string = "de aici primul &#92;n al doilea pana aici";
# Folosim nl2br pentru a transforma liniile(&#92;n) in <br/>
# Folosim $n pentru a reprezenta valoarea unei grupe reprezentate de paranteze
if(preg_match('/de aici(.*?)pana aici/s', $string )){
	echo 'Expresia regulata corespunde cu stringul.';
} else{
	echo 'Expresia regulata <b>nu</b> corespunde cu stringul.';
}
?>
Output:

8. Preg Match All

int preg_match_all(string $pattern, string $subject [, array &$matches [,int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]]) Aceasta functie este folosita la crawlere, menite sa fure baze de date intr-un mod mai usor fata de cautarea si expluatarea unui SQLi sau eu de exemplu am mai folosit-o la parsarea codului XML. Dar noi nu vom da exemplu de crawler, aici este foarte mult de discutat si astept sa fii la un nivel mai avansat pentru a-ti putea explica in detaliu cum se face un crawler web.
Mai jos vei vedea un exemplu in care cautam tot ce este scris cu bold (folosind tagurile <b> si <b>)
<?php 
# Acesta nu este un crawler si un script ce parseaza informatia bolduita dintr-un cod html
$string = '<b>PHP</b> este un <b>limbaj</b> foarte <b>bun</b> comparativ cu ASP';
$gasite = '';
preg_match_all('/<b>(.*?)</b>/i', $string, $gasite);
echo '<pre>'.print_r($gasite[1], true).'</pre>';
?>
Output:

8. Delimitatori

Am lasat acest capitol la sfarsit deoarece nu este chiar asa de important dar este necesar sa-l stiti. Noi in exemplele anterioare am folosit doar delimitatorul / care este recomandat pentru PHP sau alte limbaje precum JavaScript. Retineti sa nu folositi alti delimitatori inafara de / doar un este nevoie, nu-i folositi pentru a arata ca-i stiti sau a infrumuseta codul, delimitatorul / exprima mult mai bine ca acolo este vorba de o expresie regulata.
Insa nu toate caracterele pot fi folosite ca delimitatori, singurele caractere ce pot fi folosite ca delimitatori le gasiti in lista urmatoare:
  • /
  • #
  • @
  • &
  • "
  • '
  • ~
  • `
  • %
Exemplu de folosire ca delimitator un caracter din lista de mai sus inafara de caracterul /:
<?php  
$string = 'Mie imi place ASP.';
// Observati ca folosim delimitatorul # si nu /
$string = preg_replace('#ASP#', 'PHP', $string);
echo $string;
?>
Output:

Nu uitati sa nu folositi alti delimitatori inafara de cei prezentati de mine in lista de mai sus deoarece va genera o eroare.

10. Regex-uri utile

Am creat si acest capitol pentru a insira regex-uri utile spre a va ajuta sa nu mai pierdeti timpul sa le creati voi de fiecare data. Pentru o cautare mai rapida am pus toate pattern-urile utile intr-un tabel dar mai jos aveti si exemple pentru ele.
Pattern Descriere
/^[a-zA-Z0-9_-]{3,30}@[a-zA-Z0-9-]{3,30}.[a-zA-Z]{1,4}$/ Testeaza un e-mail daca este valid.
/^(https?://)?(www.)?[a-zA-Z0-9-.]{3,30}.[a-zA-Z]{1,4}$/ Testare web site daca este valid
/^(https?://){1}(www.)?[a-zA-Z0-9-.]{3,30}.[a-zA-Z]{1,4}([a-zA-Z0-9\_/-%&?=.#,]*)$/ Testare URL daca este valid.
  • Testare adresa e-mail daca este valida
    Exemplul acesta l-am mai dat dar il voi mai da odata pentru a te scutii sa mai stai sa-l cauti:
    <?php  
    if(isset($_GET['email'])):
    	$adresaEmail = trim(htmlentities($_GET['email'], ENT_QUOTES));
    	# Folosim caracterul  in fata caracterului - pentru a putea folosii caracterul - fara a reprezenta un operator
    	$pattern = '/^[a-zA-Z0-9_-]{3,30}@[a-zA-Z0-9-]{3,30}.[a-zA-Z]{1,4}$/';
    	if(preg_match($pattern, $adresaEmail)){
    		echo 'Adresa de e-mail este corecta.';
    	} else{
    		echo 'Adresa de e-mail nu este corecta.';
    	}
    	echo '<hr/><a href="?">Doresc sa testez din nou.</a>';
    else:
    	echo '<form>';
    		echo '<input type="text" name="email" placeholder="Introdu o adresa de e-mail"/>';
    		echo '<input type="submit" value="Verifica daca este valida"/>';
    	echo '</form>';
    endif;
    ?>
    
    Poti testa acest cod in iframe-ul de mai jos:


  • Testare web site daca este valid
    Aveti grija , acest pattern nu testeaza si daca un url este valid deci path-ul nu este permis.
    <?php 
    if(isset($_GET['site'])):
    	$adresaEmail = trim(htmlspecialchars($_GET['site'], ENT_QUOTES));
    	# Folosim caracterul  in fata caracterului - pentru a putea folosii caracterul - fara a reprezenta un operator
    	$pattern = '/^(https?://)?(www.)?[a-zA-Z0-9-.]{3,30}.[a-zA-Z]{1,4}$/';
    	if(preg_match($pattern, $adresaEmail)){
    		echo 'Web site-ul este valid.';
    	} else{
    		echo 'Web site-ul nu este valid.';
    	}
    	echo '<hr/><a href="?">Doresc sa testez din nou.</a>';
    else:
    	echo '<form>';
    		echo '<input type="text" name="site" placeholder="Introdu site-ul"/>';
    		echo '<input type="submit" value="Verifica daca este valid"/>';
    	echo '</form>';
    endif;
    ?>
    
    Poti testa codul in iframe-ul de mai jos:
  • Testare URL daca este valid
    <?php 
    if(isset($_GET['url'])):
    	$adresaEmail = trim(htmlspecialchars($_GET['url'], ENT_QUOTES));
    	# Folosim caracterul  in fata caracterului - pentru a putea folosii caracterul - fara a reprezenta un operator
    	$pattern = '/^(https?://){1}(www.)?[a-zA-Z0-9-.]{3,30}.[a-zA-Z]{1,4}([a-zA-Z0-9\_/-%&?=.#,]*)$/';
    	if(preg_match($pattern, $adresaEmail)){
    		echo 'URL-ul este valid.';
    	} else{
    		echo 'URL-ul nu este valid.';
    	}
    	echo '<hr/><a href="?">Doresc sa testez din nou.</a>';
    else:
    	echo '<form>';
    		echo '<input type="text" name="url" placeholder="Introdu url-ul"/>';
    		echo '<input type="submit" value="Verifica daca este valid"/>';
    	echo '</form>';
    endif;
    ?>
    
    Poti testa codul in iframe-ul de mai jos:


Ti-a placut articolul? Asigura-te ca-ti dam de veste cand publicam altele noi.


Tags: Curs Php, Php, Tutoriale, Programare Web

Comments Nota 0 din 0