In questo articolo analizzeremo estensivamente diversi metodi che funzionano con le espressioni regolari.
str.match(regexp)
Il metodo str.match(regexp) trova corrispondenze di regexp all’interno della stringa str.
Ha 3 modalità:
-
Se la
regexpnon presenta la flagg, essa restituisce la prima corrispondenza sotto forma di array con i gruppi di acquisizione e le proprietàindex(posizione della corrispondenza) einput(la stringa sorgente, ovverostr):let str = "I love JavaScript"; let result = str.match(/Java(Script)/); alert( result[0] ); // JavaScript (corrispondenza completa) alert( result[1] ); // Script (primo gruppo di acquisizione) alert( result.length ); // 2 // Informazioni aggiuntive: alert( result.index ); // 7 (posizione della corrispondenza) alert( result.input ); // I love JavaScript (stringa sorgente) -
Se la
regexppresenta la flagg, restituisce un array contenente tutte le corrispondenze sotto forma di stringhe, senza i gruppi di acquisizione o ulteriori dettagli. -
Se non esistono corrispondenze, indipendentemente dalla presenza o meno della flag
g, ci viene restituitonull.È una differenza sottile, ma importante. Se non esistono corrispondenze, infatti, non ci viene restituito un array vuoto, ma
null. È facile sbagliare dimenticandosene, e.g.:Tuttavia, se desideriamo che il risultato sia un array, possiamo scrivere quanto segue:
let result = str.match(regexp) || [];
str.matchAll(regexp)
Il metodo str.matchAll(regexp) è una variante innovativa di str.match.
È usato prevalentemente per cercare tutte le corrispondenze con tutti i gruppi di acquisizione.
Ci sono 3 differenze rispetto a match:
- Restituisce, al posto di un array, un oggetto iterabile contenente le corrispondenze. Da esso possiamo creare un array normale usando
Array.from. - Ogni corrispondenza è restituita sotto forma di un array con i gruppi di acquisizione (lo stesso formato di
str.matchsenza la flagg). - Se non esistono risultati, restituisce un oggetto iterabile vuoto al posto di
null.
Esempio di utilizzo:
let str = '<h1>Hello, world!</h1>';
let regexp = /<(.*?)>/g;
let matchAll = str.matchAll(regexp);
alert(matchAll); // [object RegExp String Iterator], non un array, ma un oggetto iterabile
matchAll = Array.from(matchAll); // ora è un array
let firstMatch = matchAll[0];
alert( firstMatch[0] ); // <h1>
alert( firstMatch[1] ); // h1
alert( firstMatch.index ); // 0
alert( firstMatch.input ); // <h1>Hello, world!</h1>
Se usiamo for..of per accedere alle corrispondenze di matchAll, non abbiamo più bisogno di usare Array.from.
str.split(regexp|substr, limit)
Questo metodo divide una stringa utilizzando un’espressione regolare (o una sottostringa) come separatore.
Possiamo usare split con le stringhe nel seguente modo:
Possiamo dividere le stringhe tramite un’espressione regolare, allo stesso modo:
str.search(regexp)
Il metodo str.search(regexp) restituisce la posizione della prima corrispondenza, o -1 se non ne viene trovata alcuna:
La limitazione importante: search trova solamente la prima corrispondenza.
Se avessimo bisogno della posizione di una corrispondenza successiva, dovremmo usare altri mezzi, ad esempio str.matchAll(regexp) per trovarle tutte.
str.replace(str|regexp, str|func)
Questo è un metodo generico per cercare e sostituire, ed è uno dei più utili: è l’equivalente di un coltellino svizzero in questo campo.
Possiamo usarlo senza espressioni regolari, per cercare e sostituire una sottostringa:
Tuttavia, c’è un’insidia.
Quando il primo argomento di replace è una stringa, solo la prima corrispondenza sarà sostituita.
È possibile osservarlo nell’esempio sopra: solo il primo "-" è stato sostituito da ":".
Per trovare tutti i trattini, non dobbiamo usare la stringa "-", ma l’espressione regolare /-/g, obbligatoriamente con la flagg:
Il secondo argomento è una stringa di sostituzione. Possiamo usare caratteri speciali al suo interno:
| Caratteri | Azione eseguita nella stringa di sostituzione |
|---|---|
$& |
inserisce l’intera corrispondenza |
$` |
inserisce una parte della stringa prima della corrispondenza |
$' |
inserisce una parte della stringa dopo la corrispondenza |
$n |
se n è un numero a una o 2 cifre, inserisce il contenuto dell’n-esimo gruppo di acquisizione, per i dettagli consultare I gruppi di acquisizione (capturing group) |
$<name> |
inserisce il contenuto delle parentesi con il name fornito, per i dettagli consultare I gruppi di acquisizione (capturing group) |
$$ |
inserisce il carattere $ |
Per esempio:
Per situazioni che richiedono sostituzioni “intelligenti”, il secondo argomento può essere una funzione.
Essa sarà chiamata per ogni corrispondenza, e il valore restituito sarà la sostituzione.
La funzione è chiamata con gli argomenti func(match, p1, p2, ..., pn, offset, input, groups):
match– la corrispondenza,p1, p2, ..., pn– i contenuti dei gruppi di acquisizione (se ce ne sono),offset– la posizione della corrispondenza,input– la stringa sorgente,groups– un oggetto con i gruppi nominati.
Se non ci sono parentesi all’interno dell’espressione regolare, la funzione avrà solo 3 argomenti: func(str, offset, input).
Per esempio, per rendere maiuscole tutte le corrispondenze:
Per rimpiazzare ogni corrispondenza con la sua posizione nella stringa:
Nell’esempio seguente ci sono due parentesi, di conseguenza la funzione di sostituzione è chiamata con 5 argomenti: la prima è la corrispondenza completa, poi le 2 parentesi, e dopo di esse la posizione della corrispondenza e la stringa sorgente (omesse nell’esempio):
Se sono presenti numerosi gruppi, è conveniente usare i parametri rest per accedervi:
Altrimenti, se stiamo usando gruppi nominati, l’oggetto groups essi contenente è sempre l’ultimo e possiamo ottenerlo in questo modo:
Usare una funzione ci permette di adoperare un potere sostitutivo supremo, poiché essa ottiene tutte le informazioni sulla corrispondenza, ha accesso alle variabili esterne e può fare qualsiasi cosa.
str.replaceAll(str|regexp, str|func)
Questo metodo è praticamente uguale a str.replace, ma con due differenze rilevanti:
- Se il primo argomento è una stringa, sostituisce tutte le corrispondenze della stringa, mentre
replacesostituisce solamente la prima corrispondenza. - Se il primo argomento è un’espressione regolare con la flag
g, sarà restituito un errore. Con lagflag, infatti, funziona comereplace.
Il motivo principale per cui si usa replaceAll è la necessità di sostituire ogni corrispondenza in una stringa.
In questo modo:
regexp.exec(str)
Il metodo regexp.exec(str) restituisce una corrispondenza di regexp nella stringa str. A differenza dei metodi precedenti, viene chiamato su un’espressione regolare, non su una stringa.
Si comporta differentemente a seconda della presenza o meno della flag g nell’espressione regolare.
Se non c’è g, regexp.exec(str) restituirà la prima corrispondenza, esattamente come str.match(regexp). Questo comportamento non comporta niente di nuovo.
Ma se c’è una flag g, allora:
- Una chiamata a
regexp.exec(str)restituisce la prima corrispondenza e salva la posizione immediatamente successiva a essa nella proprietàregexp.lastIndex. - La successiva chiamata di tale tipo inizia la ricerca a partire dalla posizione
regexp.lastIndex, restituisce la corrispondenza successiva e salva la posizione seguente inregexp.lastIndex. - …E così via.
- Se non esistono corrispondenze,
regexp.execrestituirànulle reimposteràregexp.lastIndexa0.
Perciò le chiamate ripetute restituiscono tutte le corrispondenze una dopo l’altra, usando la proprietà regexp.lastIndex per tenere traccia della posizione di ricerca corrente.
Nel passato, prima che il metodo str.matchAll fosse implementato in JavaScript, le chiamate a regexp.exec erano usate nei loop per ottenere tutte le corrispondenze con i gruppi:
Questo approccio funziona anche adesso, anche se per i browser moderni solitamente str.matchAll è più conveniente rispetto a un loop contenente regexp.exec.
Possiamo usare regexp.exec per cercare a partire da una posizione da noi scelta impostando manualmente lastIndex.
Per esempio:
Se l’espressione regolare presenta la flag y, la ricerca sarà eseguita esattamente alla posizione regexp.lastIndex, senza andare oltre.
Sostituiamo la flag g con y nell’esempio sopra. Non ci saranno corrispondenze, perché non c’è una parola alla posizione 5:
Ciò è conveniente per le situazioni in cui abbiamo bisogno di “leggere” qualcosa dalla stringa con un’espressione regolare alla posizione esatta, non a un’altra posizione più avanti.
regexp.test(str)
Il metodo regexp.test(str) cerca una corrispondenza in una stringa str e restituisce true/false a seconda della sua esistenza.
Per esempio:
Un esempio con l’esito negativo:
Se l’espressione regolare ha la flag g, regexp.test cerca a partire dal valore della proprietà regexp.lastIndex e l’aggiorna, come fa regexp.exec.
Pertanto possiamo usarlo per cercare a partire da una posizione da noi scelta:
Se applichiamo la stessa espressione regolare globale a stringhe differenti potrebbero verificarsi risultati errati, poiché la chiamata di regexp.test aggiorna la proprietà regexp.lastIndex, per cui la ricerca in un’altra stringa potrebbe iniziare da una posizione diversa da 0.
Per esempio, qui chiamiamo regexp.test due volte sullo stesso testo, e la seconda volta fallisce:
Ciò avviene proprio perché regexp.lastIndex è diverso da 0 nella seconda prova.
Per risolvere il problema, possiamo impostare regexp.lastIndex = 0 prima di ogni ricerca, o piuttosto che chiamare metodi sull’espressione regolare, usare i metodi delle stringhe str.match/search/...: essi infatti non usano la proprietà lastIndex.