Sep 032011
 

Le espressioni regolari, o regexp, sono gli strumenti più potenti, versatili ed odiati da programmatori ed amministratori di sistema.

Permettono di esprimere con pochi caratteri lunghe ricerche di stringhe, caratteri o parole e se fatte bene portano ad ottimi risultati, mentre se sbagliate possono non darvi alcun risultato utile, e la cosa peggiore è che spesso è anche difficile capire se si è scritto o meno una giusta sintassi che copra tute le casistiche.

Ma vediamo prima cosa è una una espressione regolare:

Da Wikipedia

Una espressione regolare definisce una funzione che prende in ingresso una stringa, e restituisce in uscita un valore del tipo sì/no, a seconda che la stringa segua o meno un certo pattern.

Ad esempio, tutti gli indirizzi e-mail devono essere costituiti nel seguente modo: cominciare con una sequenza di caratteri alfanumerici, seguiti dal simbolo chiocciola, seguiti da altri caratteri alfanumerici, seguiti dal punto, seguiti da due lettere. Questa regola informale diventerebbe una regex qualora fosse codificata secondo una sintassi ben precisa e riconosciuta da un programma in grado di analizzare le stringhe.!



sintassi: Uguale per tutti i programmi / linguaggi?

Solitamente si, in javascript e in perl la sintassi è simile, preg_replace di php utilizza la sintassi di perl, mentre ereg… beh, ereg ormai è deprecato.
Anche le Ide e programmi di testo come vim, notepad++, Komodo edit, Dreamweaver, etc. supportano il search&replace con le espressioni regolari.
Diciamo che la sintassi potrebbe cambiare, ma non di molto. E comunque se imparate quella di perl potrete comunque cavarvela con qualsiasi altra variante

I metacaratteri

Nelle espressioni regolari esistono diversi “caratteri speciali” dalle diverse funzioni:

. (punto) significa qualsiasi carattere ad eccezione di quelli che identificano una riga nuova (n e r per intenderci)

Esempio

$testo = "espressioni regolari!";
preg_match_all('/./', $testo, $ris);
// Troverà tutti i caratteri

^ identifica l’inizio di una riga; inoltre all’inizio di un gruppo nega il gruppo stesso

Esempio

$testo = "espressioni regolari!";
preg_match_all('/^./', $testo, $ris);
// Troverà solamente la lettera "e"

$ identifica la fine di una riga

Esempio

$testo = "espressioni regolari!";
preg_match_all('/.$/', $testo, $ris);
// Troverà solamente "!"

| è una condizione OR

Esempio

$testo = "espressioni regolari!";
preg_match_all('/a|i|u|o|e/', $testo, $ris);
// Troverà tutte le vocali

() le parentesi tonde identificano dei gruppi di caratteri

[] le parentesi quadre identificano intervalli e classi di caratteri

questo carattere annulla gli effetti del metacarattere successivo

Esempio

$testo = "espressioni.regolari!";
preg_match_all('/\./', $testo, $ris);
// Troverà solo il punto

I quantificatori

I quantificatori, come dice il termine stesso, indicano quante volte ricercare una data sequenza di caratteri.

* (asterisco) indica 0 o più occorrenze

Esempio

$testo = "Espressioni, pesi, piume!";
preg_match_all('/s*i/', $testo, $ris);
// Troverà "ssi" di espressioni,
// "si" di pesi
// e "i" di piume

+ indica 1 o più occorrenze

Esempio

$testo = "Espressioni, pesi, piume!";
preg_match_all('/s+i/', $testo, $ris);
// Troverà "ssi" di espressioni
// e "si" di pesi

? indica 1 o 0 occorrenze

Esempio

$testo = "Espressioni, pesi, piume!";
preg_match_all('/s?i/', $testo, $ris);
// Troverà "si" e "i" di espressioni,
// "si" di pesi
// e "i" di piume

{N} ricerca esattamente n occorrenze; da ricordare che le parentesi grafe vengono considerate caratteri normali in tutti gli altri contesti

Esempio con sostituzione

$testo = "ese, esse, essse, esssse!";
$testo = preg_replace('/es{2}e/', '*', $testo);
// Ora $testo sarà "ese, *, essse, esssse!"

{N,} ricerca minimo n occorrenze; vedi sopra

Esempio

$testo = "ese, esse, essse, esssse!";
$testo = preg_replace('/es{3,}e/', '*', $testo);
// Ora $testo sarà "ese, esse, *, *!"

{N,M} ricerca minimo n occorrenze ma non superiori alle m; vedi sopra

Esempio

$testo = "ese, esse, essse, esssse!";
$testo = preg_replace('/es{2,3}e/', '*', $testo);
// Ora $testo sarà "ese, *, *, esssse!"

I quantificatori “non golosi” (ungreedy)

Quasi tutti inciampano prima o poi in questo problema: se utilizzo una espressione del tipo /”.*”/ troverò tutte le parole racchiuse tra doppi apici? Purtroppo no!
Questo perché i quantificatori normali sono “golosi” (in inglese greedy), cioè cercano l’occorrenza il più grande possibile.
Vediamo con un esempio:

Esempio

$testo = 'class="pluto" id="pippo"';
preg_match_all('/".*"/', $testo, $ris);
// Troverà un'unica occorrenza:
// "pluto" id="pippo"

Come vedete non è il risultato sperato! Come fare quindi?
Basta aggiungere un punto interrogativo alla fine dei nostri quantificatori

Esempio

$testo = 'class="pluto" id="pippo"';
preg_match_all('/".*?"/', $testo, $ris);
// Ora troverà "pluto" e "pippo" !

Questo vale per qualsiasi quantificatore descritto in precedenza!

Le classi e gli intervalli

Le classi determinano un elenco di caratteri, di classi di caratteri o di POSIX (vedi la sezione successiva) da ricercare. Vengono racchiusi tra parentesi quadre e possono essere seguiti dai quantificatori.

Esempio

$testo = 'Questa è una stringa lunga lunga di esempio';
preg_match_all('/[aiuoe]{2}/', $testo, $ris);
// L'espressione ricercherà due vocali consecutive,
// quindi troverà "ue" e "io"

Per identificare un intervallo invece si utilizza il segno meno ( – ). Per esempio a-z identificherà tutti i caratteri minuscoli dalla a alla z, F-R i caratteri maiuscoli dalla F alla R, 0-5 i numeri da 0 a 5 e così via.

Esempio

$testo = 'caratteri 16sdf456 e un colore esadecimale 94fa3c ';
preg_match_all('/[0-9a-f]{6}/', $testo, $ris);
// L'espressione ricercherà 6 caratteri che siano numeri o lettere dalla a alla f
// quindi troverà "94fa3c"

Il carattere ^, che se posto subito dopo la parentesi quadra aperta nega tutto l’intervallo, cioè indica di non ricercare i caratteri inclusi.

Esempio

$testo = 'Questa è una stringa lunga lunga di esempio';
preg_match_all('/[^aiuoe ]{3}/', $testo, $ris);
// L'espressione ricercherà 3 lettere che non siano vocali o spazi
// quindi troverà solamene "str"

Le classi di caratteri e i POSIX

Le classi di caratteri e i POSIX servono per specificare una serie di caratteri allo stesso tempo, senza dover scomodare i gruppi.

Classe : w
Corrisponde a : [a-zA-Z0-9_]
Descrizione: ricerca un carattere “parola” (w sta per word), cioè lettere, numeri e “_”
Esempio:

$testo = "[[Le_Regex sono_belle!!!]]";
preg_match_all('/\w+/', $testo, $ris);
// Troverà "Le_Regex" e "sono_belle"

Classe: d
Corrisponde a : [0-9]
Descrizione: ricerca un numero (d sta per digit)
Esempio:

$testo = "123 stella! 456 cometa!";
preg_match_all('/\d+/', $testo, $ris);
// Troverà "123" e "456"

Classe: s
Corrisponde a: [ trnvf]
Descrizione: ricerca uno spazio, comprese tabulazioni e caratteri di fine riga
Esempio:

$testo = "manuale sulle
          espressioni regolari!";
$testo = preg_replace('/\s+/', '', $testo);
// Ora testo sarà manualesulleespressioniregolari!

Queste 3 classi hanno un corrispettivo di negazione se si utilizza la stessa lettera però maiuscola.
Così ad esempio D ricerca qualsiasi cosa non sia un numero

Classe: [:ALNUM:]
Corrisponde a: [a-zA-Z0-9]
Descrizione: Ricerca caratteri alfanumerici, senza “_”
Esempio

$testo = "[[Le_Regex 123 sono_belle!!!]]";
preg_match_all('/[[:alnum:]]+/', $testo, $ris);
// Troverà "Le","Regex", "123",
// "sono" e "belle"

Classe: [:ALPHA:]
Corrisponde a: [a-zA-Z]
Descrizione: Ricerca caratteri alfabetici
Esempio

$testo = "[[Le_Regex 123 sono_belle!!!]]";
preg_match_all('/[[:alpha:]]+/', $testo, $ris);
// Troverà "Le","Regex", "sono" e "belle"

Classe: [:BLANK:]
Corrisponde a: [ t]
Descrizione: ricerca solo spazi e tabulazioni
Esempio

$testo = "questa è una prova
	con spazi e tabulazioni";
$testo = preg_replace('/[[:blank:]]+/', '', $testo);
/* $testo ora sarà:
questaèunaprova
conspazietabulazioni
*/

Classe: [:LOWER:]
Corrisponde a: [a-z]
Descrizione: ricerca lettere minuscole
Esempio

$testo = "ESPRESSIONI regolari";
preg_match_all('/[[:lower:]]+/', $testo, $ris);
// Troverà "regolari"

Classe: [:UPPER:]
Corrisponde a: [A-Z]
Descrizione: ricerca lettere maiuscole
Esempio

$testo = "ESPRESSIONI regolari";
preg_match_all('/[[:lower:]]+/', $testo, $ris);
// Troverà "ESPRESSIONI"


I modificatori

Ogni operazione di ricerca può utilizzare vari modificatori, che, come dice il nome stesso, possono modificare i criteri di ricerca predefiniti.
Questi modificatori devono essere posizionati alla fine della stringa di ricerca, subito dopo il carattere di limitazione.
È possibile combinare più effetti accodando senza spazi i modificatori (per esempio: /imsu applicherà tutti e 4 gli effetti sotto descritti).

i la ricerca diventa case-insensitive, cioè maiuscole e minuscole vengono considerate uguali

$testo = "Le Espressioni Regolari sono regolari?";
preg_match_all('/regolari/i', $testo, $ris);
// Troverà sia "regolari" che "Regolari"

m le ricerca verrà considerate “per riga”, cioè le ancore tipo “^” e “$” verranno applicate per ogni riga di testo

$testo = 'Espressioni Regolari
Espressioni in perl
Espressioni php';
preg_match_all('/^Espressioni/m', $testo, $ris);
// Troverà tutte e 3 le "Espressioni"
// e non solo la prima

s il testo viene considerato un’unica riga e “.” ora identifica anche i caratteri di fine riga, che normalmente non troverebbe

$testo = 'Espressioni Regolari
Espressioni in perl
Espressioni php';
preg_match('/perl.Espressioni/s', $testo);
// la ricerca avrà successo

u vengono abilitati i caratteri Unicode estes, come x{10FFFFF}

$testo = '紫の触手、緑の触手';
preg_match('/\x{89e6}\x{624b}/u', $testo, $ris);
// la ricerca avrà successo

U attiva l’opzione ungreedy a tutti i quantificatori

$testo = 'class="pluto" id="pippo"';
preg_match_all('/".*"/U', $testo, $ris);
// equivale a /".*?"/ troverà sia "pluto" che "pippo"

Le ancore

Le ancore identificano la posizione in cui ricercare il nostro testo.

^ identifica l’inizio della stringa; con il modificatore /m identifica l’inizio di ogni riga

$testo = 'Questo è un esempio
sulle Espressioni Regolari
nella sintassi di perl';
preg_match_all('/^[\w]+/m', $testo, $ris);
// la ricerca troverà "Questo", "sulle" e "nella"

$ identifica la fine della stringa; con il modificatore /m identifica la fine di ogni riga

$testo = 'Questo è un esempio
sulle Espressioni Regolari
nella sintassi di perl';
preg_match('/[\w]+$/m', $testo, $ris);
// la ricerca troverà
// "esempio", "Regolari", "perl"

A similmente a ^, identifica solo l’inizio della stringa, anche se è presente il modificatore /m

$testo = 'Questo è un esempio
sulle Espressioni Regolari
nella sintassi di perl';
preg_match_all('/\A[\w]+/m', $testo, $ris);
// la ricerca troverà "Questo"

Z similmente a $, identifica solo la fine della stringa, anche se è presente il modificatore /m

$testo = 'Questo è un esempio
sulle Espressioni Regolari
nella sintassi di perl';
preg_match_all('/[\w]+\Z/m', $testo, $ris);
// la ricerca troverà "perl"

b indentifica il punto tra due caratteri che siano w a sinistra e non w a destra

$testo = 'condor daino dingo elefante';
preg_match_all('/\bd\w+/', $testo, $ris);
// la ricerca troverà solo le parole che iniziano
// con la lettera d, cioè "daino" e "dingo"

B identifica l’opposto di b

$testo = 'condor daino dingo elefante';
preg_match_all('/\Bd\w+/', $testo, $ris);
// la ricerca troverà solo una serie di caratteri
// che iniziano con d la quale non sia l'inizio di
// una parola, in questo caso "dor"

I caratteri speciali

Chi ha un po’ di conoscenza di php o di perl avrà già avuto a che fare con quei segnaposto che identificano dei caratteri speciali, come quelli di fine riga o le tabulazioni. Tali segnaposto iniziano tutti con il carattere
Ecco un elenco molto più che dettagliato, da sottolineare l’importanza di Q!!!

t tabulazione (HT, TAB)
n fine riga (LF, NL)
r ritorno a capo (CR)
Q disabilita qualsiasi metacarattere presente fino a E molto utile per inserire delle variabili nella stringa

$variabile = '[\w\s]+';
$testo = "Questo testo [\w\s]+[\w\s]+ ha regex al suo interno!";
 
$testo1 = preg_replace('/'.$variabile.'/', '', $testo);
// $testo1 senza sarà "[\\]+[\\]+!"
 
$testo2 = preg_replace('/\Q'.$variabile.'\E/', '', $testo);
// $testo2 invece sarà "Questo testo  ha regex al suo interno!"

E vedi sopra
Nnn carattere in forma ottale dove n è un numero da 0 a 7
Xnn carattere in forma esadecimale dove n è un numero… esadecimale
f form feed (FF)
a alarm/bell (BEL)
e escape (BEL)

I gruppi

I gruppi vengono racchiusi dalle parentesi tonde e diventano essenziali nel momento della sostituzione, poiché è possibile richiamarli. Un esempio per chiarire tutto:

$testo = "Questo è una data formato mysql: 2010-01-28";
$testo = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', 'Questa è una data in formato europeo: $3/$2/$1', $testo);
// ora $testo sarà "Questa è una data in formato europeo: 28/01/2010"

Come vedete l’espressione contiene tre gruppi e nella sostituzione compaiono dei dollari seguiti da un numero: questo numero rappresenta il testo trovato dal gruppo corrispondente. Così $1 identificherà il primo gruppo, $2 il secondo e così via.
Nei gruppi inoltre è possibile aggiungere un’espressione logica “OR”, cioè poter ricercare una serie di caratteri oppure un’altra

$testo = "Si dice ha piovuto o è piovuto in italiano?";
$testo = preg_replace('/\s+((ha|è)\s+piovuto)\s+/', ' è nevicato ', $testo);
// L'espressione cercherà "ha piovuto" oppure "è piovuto" seguiti o preceduti da spazi;
// $testo ora sarà "Si dice è nevicato o è nevicato in italiano?"

Conclusioni

Finisce qui l’introduzione alle espressioni regolari, vi suggerisco di utilizzare alcuni software come JRegex , regexxer oppure cheat sheet può essere veramente utile.

Riferimenti:

  • (English) Zorin OS 9 Core Review: As good as Linux Mint 17!
  • Come far ripartire Linux automaticamente in caso di Kernel Panic
  • Linux AIO alcune delle distribuzioni più comuni in una ISO
  • Come condividere su linux l’output dei vostri comandi shell
  • Come cambiare la password di un utente in linux
  • flattr this!

      4 Responses to “Guida alle espressioni regolari con esempi”

    1. Correction: You wrote:
      $text = “espressioni regolari!”;
      preg_match_all(‘/^./’, $text, $ris);
      // It will find only the letter “E”

      when in fact it will find only the character “e”.

    2. utilissima!

     Leave a Reply

    (required)

    (required)


    *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>