Menu

Regex in Python: modulo re, pattern, gruppi e sostituzioni

Un'introduzione pratica al modulo re di Python: ricerca, corrispondenze, gruppi di cattura, sostituzioni e i pattern che userai più spesso.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Quando usare le regex

Le espressioni regolari sono un piccolo linguaggio per descrivere schemi nel testo. Sono potenti ed è facile abusarne.

Prima di ricorrere a re, chiediti se bastano i normali metodi delle stringhe. .split(), .replace(), .startswith(), "target" in text: sono più veloci, più leggibili e meno soggetti a errori della regex equivalente. Tieni le regex per quando lo schema che ti interessa è davvero strutturato ma troppo flessibile per operazioni su stringhe fisse: indirizzi email, numeri di telefono, righe di log con una forma nota, frammenti di HTML o Markdown, qualsiasi ricerca del tipo "trova questo genere di cosa".

Il vocabolario di base

Un pattern regex è una stringa che descrive cosa stai cercando. Qualche mattoncino:

  • .: un qualsiasi carattere singolo
  • \d: una qualsiasi cifra (0-9)
  • \w: un qualsiasi carattere di "parola" (lettera, cifra, trattino basso)
  • \s: un qualsiasi carattere di spaziatura
  • ^: inizio della stringa
  • $: fine della stringa
  • [abc]: uno qualsiasi tra a, b o c
  • [^abc]: qualsiasi carattere tranne a, b, c
  • a|b: a oppure b
  • *: zero o più occorrenze dell'elemento precedente
  • +: una o più
  • ?: zero o una
  • {3}: esattamente 3
  • {2,5}: tra 2 e 5
  • ( ... ): gruppo (cattura la corrispondenza al suo interno)

Basta questo per la maggior parte delle regex del mondo reale.

Le funzioni principali

re.search(pattern, text) trova la prima corrispondenza in qualsiasi punto della stringa. Restituisce un oggetto match oppure None:

Usa sempre una raw string (r"...") per i pattern regex. Altrimenti Python cerca di interpretare le barre rovesciate come escape di stringa e ottieni un pattern diverso da quello che hai scritto.

re.match(pattern, text) è come search, ma trova corrispondenze solo all'inizio:

Il più delle volte ti serve search.

re.findall(pattern, text) restituisce tutte le corrispondenze non sovrapposte sotto forma di lista:

Nota che findall restituisce stringhe, non oggetti match. Se il pattern ha un solo gruppo, ottieni il contenuto del gruppo. Con più gruppi, ottieni una lista di tuple.

Gruppi di cattura

Le parentesi in un pattern catturano ciò che corrisponde al loro interno:

I gruppi con nome di solito sono più chiari:

Quando la regex ha più di un gruppo, dargli un nome rende il codice di estrazione molto più facile da seguire.

Sostituire con re.sub

re.sub(pattern, replacement, text) sostituisce ogni corrispondenza:

Questo elimina tutto ciò che non è una cifra. La sostituzione può fare riferimento ai gruppi catturati con \1, \2, ecc.; nelle raw string, \g<1> è più chiaro:

Puoi anche passare una funzione come sostituzione. È utile per trasformazioni che non sono un semplice scambio:

Compilare i pattern per riutilizzarli

Se usi lo stesso pattern molte volte, soprattutto in un ciclo, compilalo una volta sola:

I pattern compilati espongono gli stessi metodi (search, match, findall, sub) senza il pattern come primo argomento. Un po' più efficienti, spesso più leggibili.

Flag

Modificatori comuni, passati come argomento flags= o combinati con l'OR:

  • re.IGNORECASE (re.I): corrispondenza senza distinzione tra maiuscole e minuscole.
  • re.MULTILINE (re.M): ^ e $ corrispondono all'inizio e alla fine di ogni riga, non solo ai confini della stringa.
  • re.DOTALL (re.S): . corrisponde anche agli a capo (di default non lo fa).
  • re.VERBOSE (re.X): consente spazi e commenti # nel pattern, per la leggibilità.

re.VERBOSE è particolarmente utile per i pattern complessi:

Le regex su più righe e commentate sono enormemente più facili da mantenere di righe singole indecifrabili.

Greedy contro lazy

I quantificatori (*, +, ?, {n,}) sono greedy (avidi) di default: prendono quanto più testo possibile. Aggiungi un ? per renderli lazy (pigri):

La versione greedy cattura l'intera sottostringa da <b> a </i>, probabilmente non quello che volevi. Il lazy .+? si ferma al primo >.

(Nota a margine: in produzione non analizzare davvero l'HTML con le regex. Usa html.parser o BeautifulSoup. L'esempio qui sopra serve solo a illustrare il comportamento greedy.)

Un esempio realistico

Analizzare le righe di un semplice formato di log:

Tanta potenza in poche righe.

Qualche buona abitudine

  • Usa sempre le raw string per i pattern.
  • Parti dal pattern più semplice che funziona; restringilo dopo.
  • Usa i gruppi con nome appena hai più di un gruppo.
  • Compila i pattern che riutilizzerai.
  • Le regex sono più lente dei normali metodi delle stringhe. Se basta .split(), usa .split().

Prossimo argomento: errori e debug

Qui si chiude il giro sui dati reali: file, JSON, CSV, HTTP, date e regex. Prima o poi, però, qualsiasi programma reale incontra un errore, e saper leggere bene i traceback di Python è la singola abilità di debug più importante che puoi acquisire. L'ultimo capitolo parla delle eccezioni e degli errori specifici che incontrerai più spesso.

Domande frequenti

Cos'è una regex in Python?

Un'espressione regolare (regex) è un piccolo linguaggio per descrivere schemi nel testo. Il modulo re di Python ti permette di cercare pattern, estrarne dei pezzi e sostituire le corrispondenze. Per operazioni semplici sulle stringhe è eccessivo (prova prima metodi come .split() o .replace()), ma per la ricerca di schemi strutturati è imbattibile.

Che differenza c'è tra re.match e re.search?

re.match trova corrispondenze solo all'inizio della stringa. re.search scandisce l'intera stringa e trova la prima corrispondenza in qualsiasi punto. Nel dubbio, usa search: corrisponde meglio all'intuizione.

Devo usare sempre le raw string per i pattern regex?

Sì. I pattern regex contengono spesso barre rovesciate (\d, \s, \b), che le stringhe Python interpretano come sequenze di escape. Aggiungere il prefisso r, come in r'\d+', dice a Python di prendere la stringa alla lettera, e così la regex resta leggibile.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA