Vai al contenuto
LeedyBox
Sostieni

Nozioni di base sulle espressioni regolari

Un’espressione regolare (regex) è un pattern che descrive un testo. Questa guida tratta gli elementi che userai più spesso e le insidie che causano corrispondenze lente o inattese.

Caratteri letterali e classi di caratteri

La maggior parte dei caratteri corrisponde a sé stessa: il pattern cat trova il testo "cat". Alcuni caratteri hanno un significato speciale, come . * + ? ( ) [ ] { } ^ $ | \. Per cercarne uno alla lettera, esegui l’escape con una barra rovesciata, ad esempio \. per un punto.

Una classe di caratteri corrisponde a un carattere di un insieme. [abc] corrisponde ad a, b o c; [a-z] corrisponde a una lettera ASCII minuscola; [^0-9] corrisponde a qualsiasi carattere che non sia una cifra. Le abbreviazioni più comuni sono \d (cifra), \w (lettera, cifra o trattino basso), \s (spazio bianco) e i loro opposti \D, \W e \S. Il punto . corrisponde a qualsiasi carattere tranne un a capo.

In JavaScript, \w e \d coprono solo i caratteri ASCII. Per trovare le lettere di qualsiasi lingua, usa una proprietà Unicode come \p{L} con il flag u.

Quantificatori e ancore

I quantificatori indicano quante volte può ripetersi l’elemento precedente:

Sintassi Significato Esempio
* 0 o più ab* corrisponde ad a, ab, abbb
+ 1 o più \d+ corrisponde a 7 o 2026
? 0 o 1 colou?r corrisponde a color e colour
{n,m} Tra n e m \d{2,4} corrisponde a un numero da 2 a 4 cifre

Le ancore corrispondono a una posizione anziché a un carattere. ^ è l’inizio e $ la fine dell’input (o di ogni riga con il flag m). \b è un confine di parola, quindi \bcat\b trova "cat" ma non "concatenate". Quando convalidi un valore intero, ancora entrambe le estremità: ^\d{5}$ accetta esattamente cinque cifre e nient’altro.

Gruppi e catture

Le parentesi raggruppano parte di un pattern in modo che un quantificatore o un’alternativa si applichi a essa: (ab)+ ripete "ab" e (jpg|png) corrisponde a una delle due parole. Un gruppo normale inoltre cattura il testo trovato, che puoi riutilizzare in una sostituzione come $1, $2 e così via.

I gruppi con nome, come (?<year>\d{4}), rendono i pattern più leggibili e possono essere richiamati come $<year>. Se ti serve solo il raggruppamento, un gruppo senza cattura (?:...) evita di creare una cattura inutilizzata. Il Tester RegEx di LeedyBox elenca ogni corrispondenza con i relativi gruppi di cattura e mostra in anteprima le sostituzioni.

Flag

I flag cambiano il comportamento dell’intero pattern. I flag JavaScript più comuni sono:

  • g (global): trova tutte le corrispondenze invece della sola prima.
  • i (ignore case): considera uguali maiuscole e minuscole.
  • m (multiline): ^ e $ corrispondono a ogni a capo.
  • s (dotAll): anche . corrisponde agli a capo.
  • u (unicode): abilita la corrispondenza consapevole di Unicode e le classi \p{...}.

JavaScript ha anche y (sticky) e d (indici delle corrispondenze), supportati anch’essi dal tester.

Avido o pigro, e backtracking catastrofico

Per impostazione predefinita i quantificatori sono avidi (greedy): trovano quanti più caratteri possibile e poi ne restituiscono alcuni se il resto del pattern non corrisponde. Sul testo <b>bold</b>, il pattern <.+> corrisponde all’intera stringa. Aggiungendo ? il quantificatore diventa pigro (lazy), quindi <.+?> corrisponde al solo <b>. Una classe negata come <[^>]+> è spesso più chiara e più veloce.

La maggior parte dei motori regex, compreso quello di JavaScript, usa il backtracking. Quantificatori annidati come (a+)+$ o alternative che si sovrappongono possono costringere il motore a provare un numero enorme di combinazioni quando una corrispondenza fallisce, il che può bloccare una pagina o un server. Questo fenomeno è noto come backtracking catastrofico e, con input non attendibili, può essere sfruttato per attacchi denial-of-service (ReDoS). Evita di annidare quantificatori sugli stessi caratteri, preferisci classi specifiche a .* e prova i pattern con input lunghi che non corrispondono.

Le varianti di regex differiscono

Non esiste un unico standard per le regex. JavaScript, Python, Java, .NET, PCRE (usato da PHP), Go e i database supportano ciascuno una sintassi leggermente diversa. Lookbehind, quantificatori possessivi, sintassi dei gruppi con nome, classi Unicode e sintassi di sostituzione variano. Il motore RE2 di Go, ad esempio, non supporta lookaround né backreference.

Il Tester RegEx di LeedyBox usa il motore JavaScript del tuo browser. Un pattern che funziona lì potrebbe richiedere modifiche in un altro linguaggio, quindi provalo di nuovo dove verrà eseguito.

Domande frequenti

Perché il mio pattern trova solo la prima occorrenza?

Senza il flag g, JavaScript si ferma dopo la prima corrispondenza. Attiva g per trovare tutte le corrispondenze.

Una regex può convalidare gli indirizzi email?

Una regex può verificare che un valore sembri plausibile, ma non può confermare che un indirizzo esista. Il modo abituale per verificarlo è inviare un’email di conferma.

Perché ^ corrisponde una sola volta in un testo su più righe?

Per impostazione predefinita ^ e $ si riferiscono all’intero input. Attiva il flag m per farli corrispondere all’inizio e alla fine di ogni riga.