back to top

Espressioni regolari in PHP

Le espressioni regolari sono dei particolari costrutti sintattici che vengono utilizzati per le operazioni di pattern matching, cioè servono per rilevare la presenza di una sotto-stringa all’interno di una sequenza di caratteri principale. Per fare un semplice esempio, un’operazione di pattern matching sulla sequenza di caratteri "Buon natale Carla" potrebbe essere la ricerca della sotto-stringa "Carla".

Una volta individuata la sotto-stringa all’interno della sequenza di caratteri potremmo aver concluso le nostre operazioni, oppure, potremmo avere la necessità di apportare delle modifiche sulla base del risultato ottenuto; potremmo per esempio voler sostituire all’interno di "Buon natale Carla" la sotto-stringa "Carla" con un’altra, ad esempio "mamma", in questo caso verrà operata un’azione di pattern sobstitution e il risultato sarà "Buon Natale mamma"

Le espressioni regolari sono considerate, a torto, uno degli argomenti più complessi dello scripting PHP. Conosco numerosi sviluppatori veramente validi che non ne vogliono neanche sentir parlare e preferiscono non utilizzarle quando è possibile.

Nel corso di questa breve serie di articoli scopriremo che le espressioni regolari sono più semplici da utilizzare di quanto non si creda, inoltre, sono utilissime in quanto risolvono problematiche che lo sviluppatore si trova ad affrontare quotidanamente. Perchè creare funzioni personalizzate per operazioni che PHP ci consente di compiere attraverso costrutti nativi?

Le espressioni regolari non sono unicamente patrimonio del PHP, chiunque utilizza un PC da qualche tempo ha avuto a che fare con esse anche senza saperlo; pensate per esempio ai comandi "cerca" e "sostituisci" di cui sono dotati anche i più semplici editor di testo come il NotePad di Windows o il Gedit di Linux.

Tramite le espressioni regolari possiamo però eseguire operazioni ancora più raffinate come la validazione di una stringa o la formattazione di una sequanza di caratteri. Tramite una veloce ricerca sulla Rete troverete certamente numerosi esempi di espressioni regolari utilizzate per validare indirizzi di posta elettronica, dati numerici o URL.

Uno dei motivi per cui le espressioni regolari non godono di una buona fama presso coloro che utilizzano lo scripting server side in PHP sono i tempi di esecuzione ritenuti più lenti rispetto a quelli necessari per altri costrutti; l’eccezione non è del tutto immotivata, in effetti i processi di ricerca all’interno delle stringhe necessitano l’occupazione di una certa quantità di memoria da destinare ai risultati delle operazioni svolte. Avete presente la Clipbord nei sistemi operativi? Quando tagliamo o copiamo una stringa essa rappresenta lo spazio di memoria in cui viene allocato il dato su cui abbiamo operato.

In difesa delle espressioni regolari, possiamo però dire che ormai le macchine server disponibili sul mercato hanno in genere configurazioni talmente avanzate da non risentire gli effetti di questa allocazione di risorse, inoltre, raramente ci troveremo a dover eseguire matching su sequenze particolarmente lunghe ed impegnative per il sistema.

2. Le funzioni per le espressioni regolari: POSIX estesa

Ci occuperemo ora di sette funzioni native del PHP che potremo sfruttare per le nostre operazioni di pattern matching e pattern sobstitution. Queste funzioni rientrano nella tipologia (classe) POSIX estesa.

  • eregi(): da utilizzare per le operazioni di ricerca di sotto stringhe all’interno di sequenze di caratteri.
  • ereg(): permette di svolgere le stesse operazioni consentite da ereg ma è inoltre case sensitive, cioè può distinguere i caratteri tra minuscoli e maiuscoli.
  • eregi_replace(): consente di ricercare una sotto-stringa all’interno di una stringa principale e di sostituire la prima nella seconda con una terza stabilita arbitrariamente dallo sviluppatore.
  • ereg_replace(): ha una funzione analoga a quella di eregi_replace ma è inoltre case sensitive.
  • spliti(): suddivide una stringa in una matrice tramite le espressioni regolari
  • split(): ha la stessa funzione di spliti() ma è inoltre case sensitive.
  • sql_regcase(): genera un’espressione regolare per riconoscimenti senza distinguere tra maiuscole e minuscole

Passiamo ora a qualche esempio pratico. Cominciamo con eregi() e osserviamone i risultati:

<?
$str = "Sequenza di caratteri";

if (eregi("sequenza", $str))
{
  echo "Trovato!";
}else{
  echo "Non trovato!";
}
?>

eregi() cerca nel valore stringa della variabile "$str" la sotto-stringa "sequenza"; dato che questa funzione non distingue tra lettere maiuscole e minuscole, essa ignora la differenza tra "Sequenza" e "sequenza" e trova il parametro desiderato restituendo "Trovato!". Se sostituissimo eregi() con ereg() l’output sarebbe invece "Non trovato!", infatti, questa seconda funzione è case sensitive, quindi non rileva il parametro desiderato nella stringa proposta.

Passiamo ora a eregi_replace():

<?
$str = "Sequenza di caratteri";
$sostituisci = "sequenza";
$sostituto = "Insieme";
echo eregi_replace($sostituisci, $sostituto, $str);
?>

L’output del nostro piccolo script sarà "Insieme di caratteri."; in pratica eregi_replace() accetta tre parametri: la sotto-stringa da sostituire (nel nostro caso la variabile "$sostituisci"), la sotto-stringa sostitutiva ("$sostituto") e la stringa principale su cui deve essere operata la modifica ("$str"). Una volta rilevato il primo parametro nel terzo, il primo viene sostituito dal secondo. Se avessimo utilizzato ereg_replace() invece di eregi_replace(), il risultato del nostro script sarebbe stato una stampa a video del valore della variabile "$str"; infatti ereg_replace(), in quanto case sensitive, avrebbe rilevato la differenza tra tra "Sequenza" e "sequenza" e non avrebbe operato la sostituzione.

Anche per quanto riguarda la funzione spliti() proponiamo prima di tutto un breve esempio pratico:

<?
$str = "duralavita";
$array = spliti ("La", $str, 2);
print_r($array);
?>

Il cui risultato sarà:

Array ( [0] => dura [1] => vita )

Nell’esempio, spliti() suddivide una stringa utilizzando la sotto-stringa "La" come separatore; questa funzione accetta tre parametri: il separatore, la stringa da suddividere e un numero intero con funzione di limit. Per poter utilizzare split() invece di spliti() ed ottenere il medesimo risultato, il separatore avrebbe dovuto essere "la" e non "La", dato che split() è case sensitive, questo per evitare di avere come risultato un array composto da un solo valore stringa non separato:

Array ( [0] => duralavita )

Analizziamo infine la funzione svolta da sql_regcase():

<?
echo sql_regcase("Sequenza");
?>

L’output ottenuto sarà il seguente:

[Ss][Ee][Qq][Uu][Ee][Nn][Zz][Aa]

sql_regcase() restituisce un’espressione regolare in grado di riconoscere un parametro stringa a prescindere dal fatto che le lettere siano maiuscole o minuscole. Viene quindi generata una stringa composta da ciascun carattere alfabetico riportato tra parentesi quadre; le parentesi contengono il singolo carattere in formato maiuscolo e minuscolo.

3. I metacaratteri

I metacaratteri sono dei tipi particolari di caratteri utilizzati nelle espressioni regolari. Li introdurremo di seguito specificandone in breve il significato:

()le parentesi tonde delimitano una sotto-stringa
[]le parentesi quadre delimitano la classe di appartenenza dei caratteri che racchiudono
{}data una stringa o un singolo carattere, le parentesi graffe ne possono stabilire il numero, un minimo, un massimo, o un intervallo in cui un carattere o una stringa devono presentarsi
^l’accento circonflesso indica il punto d’inizio di una stringa, se si trova all’interno di una classe la nega
$il dollaro in questo caso non indica una variabile ma il punto finale di una stringa
\il backslash determina l’escape dei caratteri speciali (come ad esempio gli apici)
?il punto di domanda stabilisce l’assenza di occorrenze o una singola occorrenza di un carattere o di una stringa
+il segno più stabilisce una singola occorrenza o più occorrenze di un carattere o di una stringa
.il punto fermo rappresenta un carattere qualsiasi tranne l’acapo
|la barra (pipe), sostitutiva dell’operatore OR, restituisce TRUE quando almeno uno degli argomenti è TRUE
*l’asterisco stabilisce nessuna o più occorrenze di un carattere o di una stringa

Come anticipato, le parentesi tonde delimitano una sotto-stringa, quest’ultima viene interpretata letteralmente, cioè "(albero)" è realmente vista come insieme di caratteri "albero".

Le parentesi tonde, vengono utilizzate con i metacaratteri che indicano le ripetizioni di una sotto-stringa, ad esempio "(albero)?" indica la presenza o meno della stringa delimitata, oppure, individuano caratteri che possono essere utilizzati per operazioni da compiere su altre stringhe, come per esempio sostituzioni.

Le parentesi quadre, delimitano invece una classe di caratteri, quindi "[albero]" non viene visto come sotto-stringa, ma come classe composta dai caratteri "a,l,b..etc".

Nel caso appena esposto abbiamo indicato tutti i caratteri compresi nella classe, ma potremmo anche stabilire un determinato intervallo, come ad esempio "[b-m]", quindi la nostra classe comprenderà tutti i caratteri compresi nell’intervallo stabilito.

L’intervallo può anche essere di tipo numerico "[0-7]", oppure potremmo raffinare la nostra classe con l’ausilio di altri metacaratteri, ad esempio l’espressione

[b-m0-7\?]{1,2}

indica che i caratteri dell classe delimitata devono presentarsi da un minimo di una volta ad un massimo di due.

Come si evince dall’ultimo esempio proposto e come già anticipato, le parentesi graffe indicano un numero preciso, un minimo, un massimo o un intervallo in cui un insieme di caratteri deve presentarsi in una stringa. Quindi "{2}" indica un numero esatto (impone due presenze); "{2,}" indica un minimo (impone almeno due presenze); "{,2}" indica un massimo (impone al massimo due presenze); "{1,2}" stabilisce un intervallo (almeno una presenza ma non più di due). Un’esempio abbastanza noto in cui possiamo trovare un impiego massiccio di metacaratteri e quello relativo alla validazione di un indirizzo di posta elettronica:

<?
$email = "mail@mail.info"; 
if(ereg("^[a-z0-9][_\.a-z0-9-]+@([a-z0-9][0-9a-z-]+\.)+([a-z]{2,4})",$email))
{ 
  echo "Indirizzo valido"; 
}else{ 
  echo "Indirizzo non valido"; 
} 
?>

Nello specifico abbiamo:

  • ^[a-z0-9] con il compito di controllare che nell’indirizzo si trovi del testo composto da caratteri compresi negli intervalli "a-z" o "0- 9" (nel nostro caso, la sotto-stringa "mail" soddisfa i controlli e dà esito positivo);
  • [_\.a-z0-9-] genera un controllo sulla presenza di caratteri come l’underscore (ma_il) o il punto (ma.il);
  • +@( controlla che nell’indirizzo sia presente il simbolo della chiocciola (mail@);
  • [a-z0-9][0-9a-z-] controlla la presenza di una sotto-stringa dopo la chiocciola (@mail) le cui caratteristiche soddisfino gli intervalli di classe indicati tra parentesi quadre;
  • +\.)+ contolla che il punto fermo sia il quarto elemento presente (mail@mail.);
  • ([a-z]{2,4}) ricerca la presenza dell’estensione finale per una lunghezza non inferiore ai 2 caratteri e non superiore ai 4 (mail@mail.info).

4. Funzioni per le espressioni regolari: sintassi Perl compatibile

PHP è un linguaggio per lo scripting server side che presenta numerose affinità con il Perl, uno dei linguaggi di programmazione più utilizzati; non stupisce quindi che le espressioni regolari in PHP possano essere utilizzate anche sfruttando una sintassi compatibile con il Perl (sintassi PCRE: Perl Compatible Regular Expressions).

Nello specifico presentiamo le sette funzioni di PHP riferite a questa tipologia di sintassi:

  • preg_grep(): genera una matrice degli elementi riconosciuti attraverso le espressioni regolari;
  • preg_match_all(): esegue un riconoscimento globale tramite le espressioni regolari;
  • preg_match(): esegue un riconoscimento con le espressioni regolari;
  • preg_quote(): inserisce il carattere per l’escape (\) nei caratteri delle espressioni regolari;
  • preg_replace(): esegue una ricerca ed una sostituzione attraverso le espressioni regolari;
  • preg_replace_callback(): esegue ricerche e sostituzioni tramite espressioni regolari utilizzando il callback;
  • preg_split(): suddivide una stringa utilizzando le espressioni regolari.

preg_grep() restituisce una matrice formata dagli elementi di un array testo che soddisfano i criteri stabiliti tramite le espressioni regolari:

<?
$array = array('mino', 'lino', 'pino', 'dino');
$array_preg = preg_grep("/pino/", $array);
print_r($array_preg);
?>

il risultato del nostro piccolo script sarà:

Array ([2] => pino)

La funzione preg_match_all() effettua una ricerca di tutte le espressioni regolari (globale) passate come parametro all’interno della stringa; gli elementi riconosciuti sono allocati all’interno di una matrice. Nell’esempio che segue abbiamo isolato tramite la funzione e le espressioni regolari tutti i valori numerici presenti un una stringa:

<?
$str = "I nani sono 7 e i fantastici 4, le possibilità di diventare ricchi 1/10";
$str .= "e quelle di diventare miliardari 0.1-0.2 su 100";

$reg_exp = "`(\d+\s?[./-]?)+`";

preg_match_all($reg_exp,$str,$output);

$nb = count($output[0]);

for($i=0; $i<$nb; $i++)
{
  echo $output[0][$i] . "<br/>";
}
?>

La funzione preg_match() esegue un riconoscimento nel parametro stringa utilizzando l’espressione regolare passata come criterio. Un caso molto noto dell’utilizzo di questa funzione e quello della validazione di un’url:

<?
$url = "http://www.lukeonweb.net";

$reg_exp = "#^http\\:\\/\\/[a-z0-9\-]+\.([a-z0-9\-]+\.)?[a-z]+#i";

if (preg_match($reg_exp, $url)) 
{ 
  echo "URL valida."; 
}else{ 
  echo "URL non valida."; 
} 
?>

preg_quote() svolge la funzione di inserire il carattere di escape backslash (\) davanti a ciascun carattere di una stringa che sia parte della sintassi di un’espressione regolare, possono così essere generate stringhe da utilizzare quali criteri di riconoscimento che contengano caratteri speciali per le espressioni regolari. Nell’esempio proposto vedremo come la funzione intercetti il carattere speciale slash (/) passato come parametro insieme alla stringa su cui effettuare la ricerca:

<?
$str = "1/3 dello stipendio per l'affitto";
$str = preg_quote($str, "/");
echo $str; 
?>

l’output ottenuto sarà il seguente:

1\/3 dello stipendio per l'affitto

preg_replace() ricerca in una stringa i criteri stabiliti dall’espressione regolare, se individua una determinata sotto-stringa, la sostituisce con un sostituto. E’ possibile specificare un limite alle sostituzioni consentite, in assenza di un limite, o per un limite uguale a "-1", saranno effettuate tutte le sostituzioni possibili. Ad esempio, nello script:

<?
$str = "Dicembre 25, 2005";
$exp = "/(\w+) (\d+), (\d+)/i";
$exp2 = "\${1}1,\$3";
echo preg_replace($exp, $exp2, $str);
?>

l’output ("Dicembre1,2005") è dovuto all’azione su "$str" dei criteri stabiliti tramite espressione regolare.

preg_replace_callback() si comporta come preg_replace(), ma ha in più il callback con cui si indica una funzione da richiamare a cui verrà passata una matrice con le sotto-stringhe riconosciute in una stringa, callback quindi restituisce la stringa da sostituire:

<?
$str = "lancia-fiamme";

function maiusc($array)
{
  return ucfirst($array[1]) . '-' . ucfirst($array[2]);
}

echo preg_replace_callback("`([a-z]+)-([a-z]+)`", "maiusc", $str);
?>

Nelle’esempio abbiamo creato una piccola funzione in grado di rendere maiuscole le iniziali minuscole di sotto stringhe separate da un trattino; l’output sarà:

Lancia-Fiamme

preg_split() restituisce una matrice di parti di una stringa suddivise con criteri stabiliti nell’espressione regolare. Nel caso in cui venga specificato un limite, vengono restituite tante parti della stringa iniziale quante quelle indicate nel limite, -1 indica"nessun limite":

<?
$str = "Salmone";
$str_split = preg_split("//", $str, -1, PREG_SPLIT_NO_EMPTY);
print_r($str_split);
echo "<br/>" . $str_split[0];
?>

L’output del nostro script sarà:

Array ([0]=> S[1]=> a[2]=> l[3]=> m[4]=> o[5]=> n[6]=> e)
S

PREG_SPLIT_NO_EMPTY è un flag cioè un ulteriore parametro che può essere passato alla funzione, se viene specificato la funzione preg_split() restituisce parti di stringa non vuoti.

Per ulteriori approfondimenti su espressioni regolari, metacaratteri, funzioni e flags, rimandiamo il lettore alla consultazione del manuale ufficiale di PHP.

Altri contenuti interessanti

Pubblicità
Claudio Garau
Claudio Garau
Web developer, programmatore, Database Administrator, Linux Admin, docente e copywriter specializzato in contenuti sulle tecnologie orientate a Web, mobile, Cybersecurity e Digital Marketing per sviluppatori, PA e imprese.

Leggi anche...

Cannot modify header information – headers already sent: come risolvere l’errore PHP

L'errore di PHP cannot modify header information - headers...

Ricavare l’estensione di un file con PHP

Quando si lavora con i file in un'applicazione web,...

GD Library: creazione, manipolazione e ridimensionamento immagini con PHP

Le librerie GD (o GD Library), sono componenti fondamentali...

PHP: impostare il fuso orario italiano

Le tue pagine PHP non mostrano l’orario corretto? Probabilmente...

5 script PHP per gestire BBCode

A volte può aversi l'esigenza di dover offrire agli...
Pubblicità