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

$text = "espressioni regolari!";
preg_match_all('/./', $text, $ris);
// Will match all characters

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

Esempio

$text = "espressioni regolari!";
preg_match_all('/^./', $text, $ris);
// It will find only the character "e"

$ identifica la fine di una riga

Esempio

$text = "espressioni regolari!";
preg_match_all('/.$/', $text, $ris);
// It will find only "!"

| è una condizione OR

Esempio

$text = "espressioni regolari!";
preg_match_all('/a|i|u|o|e/', $text, $ris);
// You will find all the vowels

() 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

$text = "espressioni.regolari!";
preg_match_all('/\./', $text, $ris);
// You will find only the . (dot)

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);
// Will match "ssi" of espressioni,
// "si" in pesi
// and "i" of word piume

+ indica 1 o più occorrenze

Esempio

$testo = "Espressioni, pesi, piume!";
preg_match_all('/s+i/', $testo, $ris);
//  Will match "ssi" of espressioni,
// and "si" in pesi

? indica 1 o 0 occorrenze

Esempio

$testo = "Espressioni, pesi, piume!";
preg_match_all('/s?i/', $testo, $ris);
// Will match "si" and "i" in espressioni,
// "si" in pesi
// and "i" si 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);
// Now $testo will be "ese, *, essse, esssse!"

{N,} ricerca minimo n occorrenze; vedi sopra

Esempio

$testo = "ese, esse, essse, esssse!";
$testo = preg_replace('/es{3,}e/', '*', $testo);
// Now $testo will be "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);
// Now $testo will be "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);
// Will find a single occurrence:
// "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);
// Now it will find "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);
// The expression will search for two successive vowels,
// so it will find "ue" and "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);
// The expression will search for 6 characters that are numbers or letters from a to f
// so it will find "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);
// The term will search for 3 letters that are NOT vowels or spaces
// s oit will find only "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);
// Will match "Le_Regex" and  "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);
// Will match "123" and "456"

Classe: \s
Corrisponde a: [ \t\r\n\v\f]
Descrizione: ricerca uno spazio, comprese tabulazioni e caratteri di fine riga
Esempio:

$testo = "manuale sulle
          espressioni regolari!";
$testo = preg_replace('/\s+/', '', $testo);
// Now testo will be 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);
// Will match "Le","Regex", "123",
// "sono" and "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);
// Will match "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 Now will be:
questaèunaprova
conspazietabulazioni
*/

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

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

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

$testo = "Le Espressioni Regolari sono regolari?";
preg_match_all('/regolari/i', $testo, $ris);
// Will match both "regolari" and "Regolari"


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 = 'Espressioni Regolari
Espressioni in perl
Espressioni php';
preg_match_all('/^Espressioni/m', $testo, $ris);
// will match all 3 "Espressioni"
// and not just the first

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('/perl.Espressioni/s', $testo);
// research will be successful

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

$testo = '紫の触手、緑の触手';
preg_match('/\x{89e6}\x{624b}/u', $testo, $ris);
// research will be successful

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

$testo = 'class="pluto" id="pippo"';
preg_match_all('/".*"/U', $testo, $ris);
// it's the same as /".*?"/ will match both "pluto" and "pippo"

U attiva l’opzione ungreedy a tutti i quantificatori

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

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('/[\w]+$/m', $testo, $ris);
// Will match
// "esempio", "Regolari", "perl"

$ 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_all('/\A[\w]+/m', $testo, $ris);
// will match only "Questo"

\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('/[\w]+\Z/m', $testo, $ris);
//will match only "perl"

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

$testo = 'condor daino dingo elefante';
preg_match_all('/\bd\w+/', $testo, $ris);
// The search will find only the words that begin
// with the letter d, so "daino" and "dingo"

\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);
// The search will find only a set of characters
// beginning with d, which is not the beginning of
// a word, in this case "dor"

\B identifica l’opposto di \b

$testo = "This is a date in mysql format: 2010-01-28";
$testo = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', 'This is a date in European format: $3/$2/$1', $testo);
// Now $testo will be "This is a date in European format: 28/01/2010"

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

$testo = "Si dice ha piovuto o è piovuto in italiano?";
$testo = preg_replace('/\s+((ha|è)\s+piovuto)\s+/', ' è nevicato ', $testo);
// This will search "ha piovuto" OR "è piovuto" followed or preceded by spaces;
// $testo now will be "Si dice è nevicato o è nevicato in italiano?"

\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 Guida alle espressioni regolari

Popular Posts:

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

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=""> <s> <strike> <strong>

(required)

(required)

*