Le espressioni regolari sono spesso viste come la “bestia nera” della programmazione. Le espressioni regolari utilizzano una sintassi inusuale, che raramente trova applicazioni frequenti e quotidiane. Questo è probabilmente uno dei motivi della loro impopolarità: ogni volta che dobbiamo leggere o scrivere un'espressione regolare ci tocca “ripassare” la grammatica, o andare a consultare qualche guida online per decifrare i simboli arcani presenti nella formula.

Un'altra difficoltà delle espressioni regolari è che, nonostante siano teoricamente in grado di presentare un comportamento cross-platform, cioè utilizzare le stesse regole su sistemi operativi diversi (e diversi linguaggi di programmazione), di fatto esistono decine di dialetti differenti, da cui l'obbligo di fare un po' di attenzione quando trasportiamo un'espressione regolare da un contesto all'altro. Per nostra fortuna, nella maggior parte degli scenari, possiamo usare delle espressioni regolari relativamente “semplici”, che si comportano in modo uniforme su tutte le piattaforme. Anzi: nella maggior parte delle situazioni possiamo trovare delle espressioni regolari già pronte all'uso, che basta copiare là dove serve.

Oggi vedremo alcuni esempi concreti, cercando di spaziare da un contesto all'altro, per mostrare come le espressioni regolari siano uno degli aspetti più portabili quando cambiamo sistema operativo o linguaggio. Questo è uno dei principali motivi del loro successo: inserendo la logica di controllo o validazione in un'espressione regolare, anziché nel codice, abbiamo la possibilità di rendere più semplice la manutenzione del software.

Concetti essenziali

Le espressioni regolari servono a identificare un pattern all'interno di una stringa. La definizione va presa in senso lato, perché un pattern può essere qualsiasi sequenza, testo o struttura estraibile dalla stringa iniziale. Al tempo stesso, la stringa che filtriamo (per mezzo dell'espressione regolare) può essere un intero file, o addirittura un insieme di file diversi. Vediamo subito qualche esempio

[abc]      qualsiasi occorrenza dei caratteri a, b o c

[a-e]      qualsiasi occorrenza dei caratteri compresi tra a ed e

La prima espressione regolare (i.e. [abc]) definisce una classe di caratteri, ovvero un insieme di caratteri, in questo caso a, b o c. Ciò significa che la stringa pippo non soddisfa mai la prima espressione, mente la stringa pappa la soddisfa due volte, perché contiene due volte il carattere a. Allo stesso modo, anche le stringhe asdqwe e bbccaa soddisfano la prima espressione regolare, anche se prive di senso (per noi umani).

La seconda espressione definisce invece la classe contenente tutti i caratteri compresi tra a ed e, ovvero: a, b, c, d ed e. In questo caso le stringhe casa, dado ed elefante soddisfano l'espressione, perché contengono almeno uno dei caratteri specificati. Di contro le stringhe pino, zio e mu non la soddisfano.

Una volta compreso il concetto di base, la sintassi delle espressioni regolari permette di definire praticamente qualsiasi pattern, ovvero qualsiasi criterio di identificazione di una stringa. Esistono espressioni regolari che controllano l'intera stringa, le possibili sotto-stringhe o i singoli caratteri (come quelle appena viste). Abbiamo espressioni in grado di identificare un numero di telefono, dire che se la stringa è un URL oppure un URI, o addirittura capire quali parti della stringa servono alla business logic dell'applicazione, e quali no.

Date le finalità di questo articolo, non possiamo presentare la sintassi completa delle espressioni regolari, ma solamente dare un riferimento alla grammatica standard, oppure suggerire qualche strumento online per testare le espressioni prima di inserirle nel codice.

Del resto non vale la pena studiare l'intera grammatica delle espressioni regolari. Nella maggioranza dei casi basta aver capito a cosa servono, cercare sul web un esempio di espressione “pronta all'uso” e poi verificarla nello scenario che ci intessa. Questa è forse la competenza più importante, quando si parla di espressioni regolari: è spesso più utile saper verificare la bontà di un'espressione regolare piuttosto che conoscere a menadito tutte le regole della sintassi.

Ecco perché preferiamo fornire qualche esempio concreto, trasmettendo il concetto per via euristica, piuttosto che dilungarci sugli aspetti teorici. Pronti? Ecco una breve carrellata di esempi pratici.

Numero di telefono con prefisso

L'espressione \d{6,13} è soddisfatta solamente se l'intera stringa è composta da cifre numeriche (simbolo \d) in quantità compresa tra 6 e 13. Un controllo di questo tipo non è rigoroso, perché non verifica che il prefisso sia corretto, ma può andare bene se ci basta controllare che la stringa non contenga caratteri dell'alfabeto, simboli strani o numeri di lunghezza errata.

Stringa alfanumerica di lunghezza compra tra 10 e 50

La formula (?s).{10,50} controlla che la stringa sia un generico testo alfanumerico (simbolo .), specificando il flag (?s) per comprendere anche i caratteri di fine linea (CR e LF). In questo caso viene richiesto che la stringa contenga almeno 10 caratteri, e meno di 50.

Data espressa nel formato yyyy-MM-dd

La seguente espressione regolare è soddisfatta solo se la stringa è una data nel formato yyyy-MM-dd, come ad esempio 2012-06-21.

 (19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])

Questo è un modo di spiegare perché, in molti casi, non vale la pena conoscere tutte le regole sintattiche delle espressioni regolari, ma risulta più efficiente verificare che un'espressione faccia davvero il suo lavoro. I tool di verifica online servono perfettamente allo scopo.

Nome di un dominio web

Concludiamo con l'espressione che controlla se una stringa è un buon candidato come hostname di un dominio web

 ^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$

L'espressione qui sopra è soddisfatta da stringhe come www.aziendeitalia.com, www.aziendeitalia42.com oppure www.aziendeitalia.42.com.

Non è invece soddisfatta dalle stringhe www.aziendeitalia_42.com oppure aziendeitalia, perché non sono hostname validi.

L'unico elemento della sintassi degno di nota, in questo caso, è forse l'uso dei simboli ^ e $ per indicare, rispettivamente, l'inizio e la fine della stringa. Pattern di questo tipo sono molti frequenti quando gestiamo domini, controlliamo la validità di un hostname o specifichiamo regole per il modulo rewrite di Apache.