Informatica di base

Quantificatori nelle regexp

Autore

Manuel Ricci

Nelle lezioni precedenti abbiamo già spiato i quantificatori, ne conosciamo vagamente il significato dalla seconda lezione del corso sui caratteri speciali. È giunto il momento però di conoscerli più a fondo e di aggiungerli alle cose che capiamo delle espressioni regolari.

Uno o più caratteri

Il carattere speciale + (più) significa “una o più occorrenze”.

Prendiamo come esempio questa espressione regolare, il cui impiego è abbastanza ovvio

1\w+@\w+\.\w+

La chiocciola è lo spoiler. Avete indovinato? Si tratta di un’espressione regolare per individuare gli indirizzi email. Purtroppo però è ben lontana dall’essere perfetta, in questo momento individua correttamente degli indirizzi email come manuel@webtea.it, ma se dovessi scrivere manuel.ricci@webtea.it non la troverebbe.

Questo perché, da come abbiamo potuto vedere nella lezione sui caratteri e bordi \w ignora i punti, ma prende in considerazione solo lettere, numeri e underscore.

Proviamo quindi con un set di caratteri

1[\w.]+@[\w.]+\.\w+

Ora entrambe le email sono state individuate, ma ancora non ci siamo. Se anteponiamo un punto davanti all’indirizzo email, la regex lo individua, punto compreso.

Come fare quindi? Forse abbiamo bisogno di un altro quantificatore.

Zero o più caratteri

Per poter risolvere il problema dove ci siamo arenati abbiamo bisogno del quantificatore * (asterisco). Significa zero o più caratteri, è molto simile a +, ma con la differenza che l’espressione precedente può essere del tutto assente.

1\w+[\w.]*@[\w.]+\.\w+

Con questa ulteriore modifica la nostra regex è già più completa ed esclude i problemi con i punti antecedenti. Non è ancora definitiva, ma è un primo esempio. Se siete curiosi una regular expression più indicata al match con un indirizzo email è simile a questa:

1^(?=[A-Z0-9][A-Z0-9@._%+-]{5,253}+$)[A-Z0-9._%+-]{1,64}+@
2(?:(?=[A-Z0-9-]{1,63}+\.)[A-Z0-9]++(?:-[A-Z0-9]++)*+\.){1,8}+[A-Z]{2,63}+$

Manca ancora qualche dettaglio per comprenderla tutta, ma ci siamo quasi.

Piccola curiosità: la specifica RFC822 stabilisce questa come regexp per validare gli indirizzi email.

Zero o uno

Archiviate le email passiamo ad un altro quantificatore, il punto di domanda ? il quale ci permette di verificare la presenza di un carattere per zero o una volta.

Il caso d’uso più frequente è quanto stai cercando di validare un URL, il protocollo HTTP, può avere un S alla fine che indica che la connessione è sicura. L’espressione regolare per individuare sia http che https è la seguente:

1https?:\/\/

Numero di ripetizioni

Anche questi visti in precedenza, la coppia di parentesi graffe { } ci permette di definire un numero specifico di ripetizioni in tre modi:

  1. Numero preciso {2}
  2. Intervallo da a {2,4}
  3. Intervallo da a indeterminato {2,}

Greediness e laziness

Supponiamo di avere questa frase:

I quantificatori nelle regular expression sono "avidi", ma possono essere anche "pigri".

e di voler individuare le parole tra virgolette. Naturalmente penseremmo a qualcosa di simile a questo:

1“.+”

L’output che ci aspettiamo è che, per l’appunto, le parole tra virgolette vengano individuate. Purtroppo, come abbiamo già ampiamente appreso, la risposta è no.

Ma cosa sta succedendo esattamente?

  • cerca la virgolette doppie
  • .+ cerca qualsiasi carattere, l’engine procede fino alla fine della riga
  • l’engine torna indietro (in gergo backtrack) per soddisfare anche quest’ultima corrispondenza

In tutto questo non c’è nulla di anomalo. Si tratta dell’ingordigia o greediness dei quantificatori. Per poterla fermare ci sono tre modi. Vediamoli

  • ”.+?” questa prima soluzione, per quanto valida, non è ottimale. L’engine è costretto a fare comunque backtrack. Qui inoltre non c’è da confondere il significato del punto di domanda. Se segue un quantificatore (come in questo caso) tramuta la greediness in laziness, ma nel caso segua un’espressione ha il significato di zero o una volta come visto in precedenza.
  • /U il flag ungreedy rende tutti i quantificatori pigri (lazy) senza usare il ?
  • “[^”]+” questa soluzione è più efficiente delle precedenti soluzioni perché evita il backtrack annullando matchando tutti i caratteri ad esclusione dei doppi apici.

In pratica

Giunti a questo punto siete pronti a scrivere un'espressione regolare che potrebbe veramente servirvi nella vita da programmatore di tutti i giorni.

L’esercizio di questa lezione è quello di scrivere un’espressione regolare capace di individuare un codice fiscale (musica incalzante di sottofondo).

Fatto?

Andiamo con la soluzione.

Partiamo intanto con vedere com’è fatto un codice fiscale RSSMRA80A01F205X, abbiamo:

  • 6 lettere maiuscole: consonanti (ma non sempre) del nome e del cognome
  • 2 caratteri numerici: anno di nascita
  • 1 carattere alfabetico: mese di nascita (A=gennaio, B=febbraio, ecc.)
  • 2 caratteri numerici: cifre del giorno di nascita (+40 per le donne)
  • 1 carattere alfabetico: prima parte che identifica il comune di nascita
  • 3 carattere numerico: seconda parte che identifica il comune di nascita
  • 1 carattere alfabetico: Carattere di controllo calcolato da un algoritmo specifico

Scrivere l’espressione regolare dovrebbe essere abbastanza semplice arrivati a questo punto:

1^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$

Gli ancoraggi di inizio e fine sono opzionali anche senza va benissimo, ma insomma ormai li abbiamo imparati, usiamoli.

Conclusioni

Perfetto! Abbiamo visto i quantificatori e come usarli nelle nostre ormai meno spaventose regular expression. Nella prossima lezione andiamo ad analizzare i gruppi e le alternative, altro importantissimo tassello per scrivere espressioni regolari sempre più complesse.

Caricamento...

Diventiamo amici di penna? ✒️

Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.

Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!

Ho in previsione di mandarti una newsletter ogni due settimane e una commerciale quando capita.