In un linguaggio ad oggetti, anche le espressioni regolari sono degli oggetti. Già… ma cosa sono le espressioni regolari? Le espressioni regolari sono pattern, ovvero sequenze di caratteri (stringhe), che grazie a generalizzazioni possono identificare insiemi di stringhe molto più complessi.
Le espressioni regolari, anche dette RegExp, formano un vero e proprio linguaggio, potentissimo, estremamente sintetico, ma altamente criptico. Si tratta di un formalismo sviluppato al di fuori di un singolo linguaggio di programmazione ed usato anche nel linguaggio JavaScript.
Una versione estremamente ridotta delle espressioni regolari è quella che usiamo normalmente per raggruppare i nomi dei file in ricerca.
Un tipico esempio che tutti conosciamo è l’uso del punto interrogativo (dell’asterisco) ad indicare caratteri singoli (a gruppo).
Se in un directory abbiamo tre file, chiamati:
file_001
file_002
file_101
filedue
Cercando “file_00?” troveremo
file_001
file_002
Usando invece l’asterisco, cercando “file*”, li troveremo tutti e quattro.
La potenza delle espressioni regolari è talmente ampia da essere filtrata anche nel linguaggio scritto. In tutte le lingue, infatti, si usa l’asterisco per terminare parole delle quali non si vuole dare un connotato di genere: anziché scrivere tutti o tutte, o entrambi senza sapere con quale è meglio iniziare, sempre più spesso si scrive tutt* (o anche altre forme equivalenti, come lo schwa (Ə).
Ovviamente, in JavaScript anche le espressioni regolari sono degli oggetti, e vanno dichiarati come costanti (con const) o come variabili (con var o let).
Esistono due modalità di dichiarazione delle espressioni regolari, implicita o esplicita:
let er1 = /abc/; let er2 = new RegExp("abc");
Il comportamento di JavaScript è diverso a seconda del tipo di dichiarazione. Per semplicità, gli esempi che vedremo usano esclusivamente il costruttore new RegExp().
Come vedremo, gli elementi di partenza per usare le espressioni regolari sono le parentesi quadre, la barra inversa, il punto, il punto interrogativo, l’asterisco, il più, il dollaro, la lettera d (minuscola e maiuscola) la lettera w (minuscola e maiuscola) e il caret (accento circonflesso):
[ ] \ . ? * + $ d D w W ^
Vediamoli in fila, senza respirare!
Le quadre [ ] includono i caratteri da analizzare, Caret ^ e dollaro $ indicano inizio e fine della stringa, punto . interrogativo ? e asterisco * selezionano parti della stringa, d minuscola indica le cifre da 0 a 9 (digits), w minuscola i caratteri alfabetici (word characters) e le maiuscole negano la lettera, ovvero D indica “tutto ciò che non è cifra e W indica “tutto ciò che non è alfabetico”.
Le RegExp hanno una sintassi molto complessa. Prima di addentrarsi in maggiori dettagli teorici, mettiamo le mani sulla pratica.
Proviamo a vedere se, partendo da una successione di cifre, possiamo stabilire se si tratta di un numero binario, ovvero se contiene solo 0 ed 1.
Definiamo l’espressione regolare binario, che accetta tutto ciò che contiene 0 ed 1; definiamo, poi, la stringa costante esempio1, pari a “01011101”; quindi, applichiamo all’espressione regolare binario il metodo test, che fa la verifica della stringa esempio:
let binario = new RegExp("[01]"); const esempio1 = "01011101"; console.log(binario.test(esempio1));
Il sistema risponde
true
In realtà, questo codice verifica che ci sia almeno una occorrenza di caratteri 0 o 1. Per essere sicuri che l’analisi si estenda all’intera stringa, serve una sintassi leggermente più complicata:
^[01]+$
Identifica + occorrenze di 0 o 1 e con controllo dell’intera stringa, dall’inizio (^) alla fine ($).
Quindi il codice:
let binario2 = new RegExp("^[01]+$"); const esempio1 = "01011101"; const esempio2 = "01019101"; const esempio3 = "0101A101"; console.log(binario2.test(esempio1)); console.log(binario2.test(esempio2)); console.log(binario2.test(esempio3));
Restituirà
true
false
false
Vediamo, ora, i metodi search e replace.
Metodo Search JavaScript
Tra i metodi disponibili c’è ovviamente la ricerca, search. Possiamo cercare se una stringa piccola è contenuta in una stringa più grande.
let stringa = "Ciao mondo!"; let ricerca = new RegExp("mondo"); let posizione = stringa.search(ricerca); console.log(posizione);
Il risultato, se la ricerca ha successo, è la posizione del primo carattere della stringa da cercare. In questo caso, ricerca ha successo e la m di mondo è in posizione 5 (si comincia da 0), quindi la risposta sarà
5
Metodo Replace JavaScript
Passiamo, ora, a vedere come funziona replace, il metodo di sostituzione.
let esempio1 = "babbo"; console.log(esempio1.replace("b", "m"));
Fornirà come risultato
mabbo
Perché la sostituzione si ferma alla prima verifica della ricerca di una b (e sostituzione con la m).
Per sostituire tutte le occorrenze bisogna agire sulla stringa in modo globale, con l’opzione g, che può essere impostata se la stringa da sostituire viene delimitata non da virgolette, ma da slash:
let esempio1 = "babbo"; console.log(esempio1.replace(/b/g, "m"));
Può essere comodo vedere come si sviluppa la stessa sostituzione usando la RegExp:
let esempio1 = "babbo"; let cambia = new RegExp("b", "g") let risultato = esempio1.replace(cambia, "m"); console.log(risultato);
La dichiarazione di cambia comprende la lettera da cambiare e l’opzione g(lobal); il metodo replace agisce sull’oggetto cambia e con la lettera m.
Il livello di complessità delle espressioni regolari può portare a risultati sorprendenti. Una possibilità che può tornare utile è affidare la sostituzione a valori definiti da funzioni.
Il formato completo del metodo replace è infatti questo:
string.replace(regexp|substr, newSubstr|function)
Data una stringa, replace accetta due parametri: il primo è l’oggetto della ricerca in forma di substringa o di espressione regolare, mentre il secondo è la componente con cui fare la modifica, in forma di nuova substringa o di funzione.
Quindi, usando come parametri due substringhe puoi vedere che questo codice
const str = "Salve a tutti! Salve a tutti!"; const newStr = str.replace("tutti", "JavaScript"); console.log(newStr);
Porta all’output
“Salve a JavaScript! Salve a tutti!”
Aggiungendo il parametro g(lobal) abbiamo il codice:
const str = "Salve a tutti! Salve a tutti!"; const newStr = str.replace(/tutti/g, "JavaScript"); console.log(newStr);
con risposta:
“Salve a JavaScript! Salve a JavaScript!”
Esempio: inversione nomi
const nomi = "VanBeurden, Ben\nLooney, Bernard\nBuffett, Warren\nToyoda, Akio"; const stringaSostituzione = "$2 $1"; const espressReg = /(\w+), (\w+)/g; var sostituisci=nomi.replace(espressReg, stringaSostituzione); console.log(sostituisci);
Vediamo cosa fa, riga per riga.
Prima di spiegare cosa faccia questo semplice programma, è necessario dettagliare una specificità delle espressioni regolari, i gruppi di caratteri. Li troviamo indicati con $1 e $2.
È importante notare che i gruppi possono essere usati solo in una stringa di sostituzione e non possono essere utilizzati per effettuare una ricerca.
In una stringa di sostituzione le componenti possono essere individuate come raggruppamenti di caratteri o gruppi.
i gruppi possono essere richiamati utilizzando il segnaposto “$” seguito dal numero del gruppo. In questo caso, la numerazione non parte da 0, ma da 1. Quindi “$1” indica il primo gruppo, “$2” il secondo, e così via.
Ad esempio, nella nostra espressione regolare /(\w+), (\w+)/ i due gruppi sono le parole (\w+), (\w+). Nella nostra stringa, il primo gruppo corrisponde al cognome e il secondo al nome, quindi si identificano come S1 ed S2. Usando la stringa di sostituzione “$2 $1”, si ottiene l’inversione del nome e del cognome.
Vediamo, ora, cosa succede, riga per riga.
- Per prima cosa, si crea una costante chiamata “nomi” che contiene un elenco di nomi e cognomi separati da un a capo, \n;
- Quindi, si crea una costante chiamata “stringaSostituzione” che contiene la stringa di sostituzione per i nomi e cognomi invertiti;
- L’espressione regolare chiamata “espressReg” individua le word di nomi e cognomi nella stringa “nomi”, in modalità globale;
- Si fanno le sostituzioni mettendo il risultato nella variabile “sostituisci”;
- Si stampa il risultato sulla console.
Javascript array foreach: il metodo foreach() JavaScript
Il metodo forEach() è una funzione del tipo di dato array in Javascript. Agisce su ciascun elemento presente all’interno dell’array stesso senza dover usare un ciclo “for” tradizionale.
Nella forma più semplice, la sua sintassi è questa:
array.forEach(function(currentValue) { // Esegui azioni qui });
Esempio: conversione da cm a pollici
Supponiamo di avere un array di numeri che rappresentano misure in centimetri. L’array è questo:
centimetri = [10, 20, 30, 40, 50]
Su questi valori si vuole svolgere una operazione- Per semplicità usiamo una semplice moltiplicazione: convertiamo la misura da centimetri a pollici, l’unità di misura anglosassone. Un pollice vale 2,54 centimetri, quindi un centimetro è circa 0,39 pollici.
Creiamo un nuovo array per i risultati, e lo chiamiamo pollici[].
Alla fine, stampiamo pollici[].
Ovviamente possiamo usare il metodo forEach().
// Creazione dell'array di numeri in centimetri const centimetri = [10, 20, 30, 40, 50]; // Creazione di un nuovo array per memorizzare i numeri convertiti in pollici const pollici = []; // Funzione per convertire centimetri in pollici function convertiCentimetriInPollici(centimetro) { return centimetro * 0.393700787; } // forEach() converte tutti i numeri in pollici centimetri.forEach(function(centimetro) { // Convertire i centimetri in pollici const pollice = convertiCentimetriInPollici(centimetro); // Aggiungere il valore convertito in pollici al nuovo array pollici.push(pollice); }); // Stampare il nuovo array di numeri convertiti in pollici console.log(pollici); L’uscita di questo programma è [3.93700787, 7.87401574, 11.81102361, 15.74803148, 19.68503935]
RegExp: Operatori
La lista degli operatori è lunga: puoi trovarli tutti, ad esempio, sul sito di Mozilla. Per comodità, oltre a quelli già visti, ecco una lista ridotta di operatori frequenti:
{n} – trova corrispondenza con il carattere o al gruppo precedente esattamente n volte
{n,} – trova corrispondenza con il carattere o al gruppo precedente n o più volte
{n,m} – trova corrispondenza con il carattere o al gruppo precedente almeno n volte, ma non più di m volte
[…] – trova corrispondenza con qualsiasi carattere tra parentesi
[^…] – trova corrispondenza con qualsiasi carattere non compreso tra parentesi
(…) – Raggruppa personaggi o operatori e crea un gruppo di cattura
(?:…) – Raggruppa personaggi o operatori senza creare un gruppo di acquisizione
\s, \S – trova corrispondenza con qualsiasi spazio bianco o non spazio bianco
\b, \B – trova corrispondenza con un limite di parola o a un limite di non parola
\n, \r, \t, \f – trova corrispondenza con nuova riga, ritorno a capo, tabulazione o feed modulo
RegExp: Metodi
I metodi principali, invece, sono:
- exec()
- test()
- match()
- search()
- replace()
- split()
ECMAScript 2020 ha aggiunto
- matchAll()
Va, poi, ricordata la famiglia di metodi associati all’oggetto interno symbol: