Skip to content

Espressioni regolari

Perché ti servono le espressioni regolari

Section titled “Perché ti servono le espressioni regolari”

Immagina di dover controllare se un indirizzo email è scritto correttamente, o di dover trovare tutti i numeri di telefono in un testo. Potresti farlo con decine di condizioni if, oppure usare uno strumento molto più potente: le espressioni regolari.


Le espressioni regolari (dette anche “regex” o “regexp”) sono una mini-lingua per descrivere schemi di testo. Servono a:

  • Verificare se una stringa corrisponde a un certo formato (“è un’email valida?”)
  • Trovare schemi in un testo (“tutti i numeri in questo paragrafo”)
  • Estrarre informazioni (“dammi solo la data da questa riga”)
  • Sostituire parti di testo (“sostituisci tutti i numeri con X”)

In Python si usano con il modulo re:

import re

I mattoncini di base: cosa significano i simboli

Section titled “I mattoncini di base: cosa significano i simboli”
SimboloSignificatoEsempio
.Qualsiasi carattere (eccetto a capo)a.c trova “abc”, “aXc”, “a3c”…
\dUna cifra (0-9)\d\d trova “42”, “07”…
\DNon una cifra
\wLettera, cifra o underscore
\sSpazio, tab o a capo
^Inizio della stringa^Ciao trova solo stringhe che iniziano con “Ciao”
$Fine della stringafine$ trova solo stringhe che terminano con “fine”
[abc]Uno tra a, b, c
[a-z]Una lettera minuscola qualsiasi
[0-9]Una cifra qualsiasi (come \d)
SimboloSignificato
*Zero o più volte
+Una o più volte
?Zero o una volta
{3}Esattamente 3 volte
{2,5}Da 2 a 5 volte

re.search() — cerca ovunque nella stringa

Section titled “re.search() — cerca ovunque nella stringa”
import re
testo = "Il mio numero è 334-1234567"
# Schema: 3 cifre, un trattino, 7 cifre
risultato = re.search(r"\d{3}-\d{7}", testo)
if risultato:
print(f"Numero trovato: {risultato.group()}") # → 334-1234567
else:
print("Nessun numero trovato")

Il prefisso r prima delle virgolette (r"...") indica una “raw string” — necessario con le regex perché alcuni caratteri come \d verrebbero interpretati in modo sbagliato.


re.match() — cerca solo all’inizio della stringa

Section titled “re.match() — cerca solo all’inizio della stringa”
import re
testo = "Ciao, mondo!"
risultato = re.match(r"Ciao", testo) # La stringa inizia con "Ciao"?
if risultato:
print("Trovato!")
else:
print("Non trovato.")

re.findall() — trova TUTTE le corrispondenze

Section titled “re.findall() — trova TUTTE le corrispondenze”
import re
testo = "Ho 3 mele, 5 banane e 2 arance."
numeri = re.findall(r"\d+", testo) # Trova tutti i gruppi di cifre
print(numeri) # ['3', '5', '2']

import re
testo = "Il prezzo è 10 euro, poi 20 euro."
nuovo = re.sub(r"\d+", "X", testo) # Sostituisce tutti i numeri con "X"
print(nuovo) # Il prezzo è X euro, poi X euro.

Come str.split(), ma puoi dividere su uno schema complesso invece che su un singolo carattere:

import re
testo = "mela; banana, uva ciliegia"
# Divide su punto e virgola, virgola o spazi (anche multipli)
parti = re.split(r"[;,\s]+", testo)
print(parti) # ['mela', 'banana', 'uva', 'ciliegia']

Estrarre parti specifiche: i gruppi con ()

Section titled “Estrarre parti specifiche: i gruppi con ()”

Le parentesi tonde creano dei gruppi — puoi estrarre separatamente ogni parte del risultato:

import re
testo = "Data di nascita: 15/03/2008"
match = re.search(r"(\d{2})/(\d{2})/(\d{4})", testo)
if match:
giorno = match.group(1) # Primo gruppo → 15
mese = match.group(2) # Secondo gruppo → 03
anno = match.group(3) # Terzo gruppo → 2008
print(f"Giorno: {giorno}, Mese: {mese}, Anno: {anno}")

Se usi lo stesso schema molte volte, “compilalo” una volta sola per rendere il codice più efficiente:

import re
schema_numeri = re.compile(r"\d+") # Compila lo schema una volta
frasi = ["Ho 3 mele", "Ho 10 banane", "nessun numero qui"]
for frase in frasi:
trovati = schema_numeri.findall(frase)
if trovati:
print(f"Trovati: {trovati}")

import re
def valida_email(email):
# Schema: caratteri@caratteri.dominio (almeno 2 lettere)
schema = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
return bool(re.match(schema, email))
print(valida_email("alice@esempio.it")) # True ← valida
print(valida_email("non_valida.com")) # False ← manca la @
print(valida_email("@dominio.it")) # False ← manca la parte prima della @
import re
def valida_telefono(numero):
# Schema: opzionalmente +39, poi 9 o 10 cifre
schema = r"^(\+39)?[0-9]{9,10}$"
return bool(re.match(schema, numero))
print(valida_telefono("3341234567")) # True
print(valida_telefono("+393341234567")) # True
print(valida_telefono("abc")) # False