Michael Denny's Blog ;]


Tutto quello che non avresti mai voluto sapere sulle Regular Expression...e se sei qui ti tocca!
Archivio Posts
Anno 2017

Anno 2015

Anno 2014

Anno 2013

Anno 2012

Anno 2010

Anno 2008

Anno 2007

[RegEx] - I primi passi con le Regular Expression

- Differenti motori di Regular Expression
Un "motore" di regular expression è un software in grado di interpretare appunto le "regular expression", basato sulla ricerca di porzioni di testo tramite "pattern" di ricerca. Solitamente, un motore è parte di un più esteso applicativo. Non si ha accesso direttamente ad esso, è l'applicazione che chiama funzioni opportune, preoccupandosi di controllare che la regular expression sia correttamente applicata a particolari file o dati.

Come spesso accade nel mondo del software, differenti motori non sono completamente compatibili tra di loro. Questo vale anche per le regular expression.
Non è possibile descrivere tutti i tipi di sintassi. Perciò, in questo blog, utilizzerò quelle definite dalla libreria di .NET di Microsoft, che del resto è decisamente diffusa. Tuttavia aggiungerò alla sezione dei link le pagine contententi le references dei vari motori di regular expression.

- Differenza tra caratteri Letterali e Speciali
La più semplice regular expression consiste in un singolo carattere alfabetico, ad esempio 'e'. Una espressione così rappresentata ricaverà la prima occorrenza di quel carattere nel testo su cui si effettua la ricerca. Se il testo fosse "Marco è un programmatore e un calciatore", la ricerca avrebbe come risultato il riscontro della prima 'e' subito dopo la 'r' finale di "programmatore". In realtà il motore di regex ignora il fatto che la 'e' sia nel mezzo di una parola. Esso la considera comunque un'occorrenza valida. Se volessimo cambiare la regola, dovremmo imporre al motore regex di seguire altre vie  utilizzando caratteri speciali per specificare che quanto cercato deve far parte di una parola intera. Vedremo come farlo più avanti.

In maniera del tutto simile, una regex 'tasti' ricava l'occorenza 'tasti' nella frase "Questa tastiera è molto comoda". L'espressione consiste in una serie di cinque caratteri alfabetici. Questo è come dire al motore di regex: trova una 't', seguita subito da una 'a', seguita subito da una 's', seguita subito da una 't', seguita subito da una 'i'.

Fate attenzione perchè i motori di regex sono case sensitive (sensibili alle minuscole e maiuscole). "tasti" non troverà occorrenze in "Tasti", a meno che non si dica al motore di regex di ignorare le differenze di case.

Tutti i precedenti pattern di ricerca erano formati da semplici caratteri alfabetici. Dato che noi vogliamo di più di una semplice ricerca letterale, abbiamo bisogno di riservare una certa serie di caratteri per un utilizzo speciale. Nei motori ci sono più o meno sempre 12 caratteri speciali, che sono i seguenti: '\', '[', ']', '^', '(', ')', '$', '.', '|', '?', '*', '+'. Questi sono spesso chiamati "metacharacters" (metacaratteri).

Se volessimo utilizzarne uno, è necessario fare il cosidetto "escape" del carattere, cioè anteporre un backslash '\' al carattere stesso. Se ad esempio volessimo eseguire la ricerca di "1+1=2", la corretta regex sarebbe "1\+1=2". senza '\', il carattere '+' avrebbe uno speciale significato, diverso da quello che vorremmo intendere noi. Notate che "1+1=2", senza backslash, è una valida regex, nessun warning o messaggio di errore verrà restituito. Semplicemente la ricerca non sarà la stessa. Inoltre nel caso in cui si volesse cercare '\' all'interno di un testo, sarebbe necessario fare l'escape anche di quest'ultimo, e quindi il pattern di ricerca per la semplice occorrenza del backslash è il seguente: "\\".

- Scrivere le Regular Expression in C#
Tutti i programmatori di C# conosceranno già bene quanto sto per scrivere, ma ho voluto comunque sottolinearlo perchè è una semplice sintassi che per utilizzare le Regular Expression in C# è fondamentale.

In C# quando si crea una stringa essa può contenere qualsiasi carattere letterale, incluse le sequenze di escape. Dato che in C# il carattere speciale per identificare una sequenza di escape è la stessa utilizzata nelle Regular Expression, è opportuno creare sempre le strighe anteponendo ai doppi apici anche il carattere '@', così da creare una stringa dove non vengano elaborate le sequenze di escape, in modo da semplificarne la scrittura di un regex.

Esempio senza l'utilizzo del carattere '@': System.Text.RegularExpressions.Regex myRegex = new System.Text.RegularExpressions.Regex("[A-Z]\\d", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

Esempio con l'utilizzo del carattere '@': System.Text.RegularExpressions.Regex myRegex = new System.Text.RegularExpressions.Regex(@"[A-Z]\d", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

- Matching dei caratteri ASCII e UNICODE
Per creare una regular expression con caratteri speciali (non scrivibili) è necessario utilizzare i seguenti metacaratteri:

\xFF (ASCII)

\uFFFF (UNICODE)

Ad esempio se volessimo includere nella nostra regex il carattere ö il corrispettivo codice ASCII sarebbe \xF6, mentre in UNICODE sarebbe \u00F6
Nel precedente esempio sarebbe sufficiente utilizzare il metacarattere ascii per individuare il carattere ö, ma se dovessimo ad esempio fare una ricerca con un carattere cinese, sarebbe indispensabile utilizzare il metacarattere per l'unicode.

- I motori RegEx ritornano sempre l'occorrenza (match) più a sinistra
Quando si esegue una regular expression su di una porzione di testo, restituirà la prima occorrenza più a sinistra.

Prendiamo ad esempio la regex "abc" eseguita sul testo "abc asd qwe abc abc", il risultato sarà il matching della prima occorrenza della sequenza di caratteri "abc", mentre le altre due occorrenze successive non saranno prese in considerazione, a patto di non lanciare il comando NextMatch oppure Matches, che tratteremo prossimamente.

- Introduzione ai Character sets (Set di caratteri)
Abbiamo già visto precedentemente come una regular expression può essere formata semplicemente da caratteri letterali, ma questo di certo non è interessante, il bello viene adesso!

Se volessimo ad esempio individuare in un grande documento tutti i numeri di telefono con una particolare sintassi?
Ecco che interviene a nostro favore il primo set di caratteri \d che è in grado di trovare un occorrenza di una cifra numerica, di conseguenza la nostra regex potrebbe essere la seguente:

\d\d\d\d-\d\d\d\d\d\d

Il testo di esempio:

bla bla 0555-574569 bla bla bla bla

La regular expression sopra scritta, descrive la sintassi che dovrà avere il nostro numero di telefono, cioè formata da una sequenza di 4 cifre numeriche, un separatore '-', e successivamente altre 6 cifre numeriche.

 Come Funziona
Il motore RegEx cerca un valore numerico. Se il primo carattere che sta testando non è una cifra numerica, si sposta in avanti di un carattere all'interno del testo e continua fino a quando non trova la prima crifra numerica.

Se per la prima occorrenza di \d è stato trovato un match, il motore RegEx va al successivo "token", cioè il successivo carattere della regular expression, che in questo caso è di nuovo \d e di conseguenza controlla ancora se il seguente carattere del testo è anche esso una cifra numerica. Se di nuovo il motore trova la cifra, si sposta al prossimo token e così via fino a che non esaurisce tutti i caratteri della regular, a questo punto restituirà il numero trovato.

Nel nostro caso la regular expression sopra descritta, restituirà il numero di telefono 0555-574569, ma attenzione perchè se il testo fosse il seguente:

bla bla 90555-5745691 bla bla bla bla

la nostra regular expression farebbe comunque il match del numero: 0555-574569, questo perchè si aspetta un carattere di separazione '-' al quinto carattere trovato, che in quest'ultimo caso è ancora una cifra numerica e non il separatore. Di conseguenza il motore è costretto a provare di nuovo la regular da capo, partendo stavolta dal carattere successivo alla prima occorrenza trovata, nel nostro caso riparte dalla cifra '0'.
Ripartendo dalla cifra '0' la regular expression viene soddisfatta fino in fondo perchè il numero è apparentenente al formato corretto, se non che, l'ultima cifra '1' non viene anch'essa inclusa nel match, e questo per il semplice fatto che il motore si ferma al carattere '9'.
Questo perchè è la cifra che esaudisce l'ultimo token della regular expression. Alla fine si è trovato uno pseudo numero di telefono, che apparentemente sembra corretto.
Per evitare che questo accada è possibile raffinare la regular aggiungendo il metacarattere \b (boundary word) che esprime il limite di parola, cioè è in grado di vedere se in quel punto esiste un limite di parola, il che vuol dire, nel nostro caso, uno spazio prima e dopo il numero.

La nuova regular expression sarà così formata:

\b\d\d\d\d-\d\d\d\d\d\d\b

In questo modo il numero nell'esempio precedente non è nel formato corretto e quindi non viene individuato.

Prossimamente vedremo anche come rendere più "elastica" una regular expression, per poter prendere, ad esempio, anche i numeri di telefono formati da prefissi a lunghezza variabile.


Stay Tuned!

Categoria: Regular Expression
giovedì, 04 ott 2007 Ore. 22.14
Calendario
aprile 2024
lmmgvsd
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345





Statistiche
  • Views Home Page: 82.388
  • Views Posts: 80.148
  • Views Gallerie: 0
  • n° Posts: 31
  • n° Commenti: 18
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003