
guide
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Validare l’input, effettuare ricerche all’interno del testo o implementare la funzione di trova e sostituisci, con le espressioni regolari di C++11
C++11 è lo standard per il linguaggio C++ approvato dopo un lungo percorso il 12 Agosto 2012. Tra le numerose funzionalità introdotte c’è il supporto nativo alle espressioni regolari.
Perché l’introduzione delle Espressioni Regolari (chiamate per brevità regex) è una novità così importante? Tra gli impieghi più frequenti delle regex in programmazione c’è la validazione dell’input, ovvero quel controllo che verifica, ad esempio, se ciò che l’utente ha inserito in un campo numerico sia un numero valido oppure no.
Prima del rilascio del nuovo standard, validare l’input significava scrivere le proprie funzioni per la verifica dei dati inseriti e per la gestione di eventuali eccezioni, oppure utilizzare librerie specializzate (come boost).
In questo articolo vedremo allora come utilizzare l’implementazione delle regex all’interno di C++11.
L’elaborazione delle espressioni regolari è già supportata da alcuni dei maggiori compilatori (fra i quali Clang++ e Visual C++ 2010 e seguenti) tuttavia, nel momento in cui scrivo, G++ 4.6 ha ancora un supporto parziale alle espressioni regolari: i sorgenti vengono compilati ma non eseguiti. Quindi per eseguire il codice di esempio di questo tutorial è bene che vi muniate di alternative valide.
Con le espressioni regolari è possibile validare un input (e molto altro) in modo semplice a patto di imparare la loro sintassi. Le regex sono infatti un modo di descrivere la struttura di una stringa (un pattern), permettendo così al computer di identificarla all’interno di un testo (matching) oppure dire se una stringa in ingresso sia dotata o no della stessa struttura.
Ad esempio ogni numero intero può cominciare opzionalmente con il simbolo “meno” (-
) e segue con una serie di cifre. Con una espressione regolare è possibile descrivere questa struttura e riconoscere immediatamente la stringa "-304"
come valida e scartare, ad esempio, la stringa "35op90"
.
Nelle espressioni regolari in C++ è possibile utilizzare diversi tipi di sintassi semplicemente passando un opzione come parametro delle funzioni. L’implementazione di default prevede però la sintassi ECMAScript ed è proprio di questa che elenchiamo gli elementi fondamentali in una piccola tabella:
Simbolo | Significato |
---|---|
. (punto) |
Qualunque carattere ad esclusione dei terminatori di riga |
[:alpha:] |
Qualunque carattere alfabetico |
[:alnum:] |
Qualunque carattere alfanumerico |
[:digit:] |
Qualunque cifra compresa fra 0 e 9 |
s |
Spazio |
[^:class:] |
Nega la classe. Ad esempio [^:digit:] significa: qualsiasi carattere che non sia una cifra |
* (asterisco) |
Zero o più ripetizioni della struttura precedente |
+ (più) |
Una o più ripetizioni della struttura precedente |
? (interrogativo) |
La struttura precedente è opzionale |
{int} |
La struttura precedente viene ripetuta esattamente int volte |
$ |
La struttura è collocata alla fine della frase |
^ |
La struttura è collocata all’inizio della frase |
| (pipe) |
Separa una serie di possibilità. Ad esempio a | b significa che può comparire il carattere a oppure il carattere b |
L’implementazione delle espressioni regolari in C++ è costituita principalmente da:
Parleremo con sufficiente dettaglio di queste funzioni negli esempi successivi.
regex
(espressioni regolari su stringhe) oppure come wregex
(espressioni regolari per stringhe wide).Iniziamo a lavorare concretamente con le espressioni regolari e vediamo come scrivere un programma C++ in grado di riconoscere se una stringa è un numero valido.
Cominciamo includendo le librerie necessarie:
#include <iostream>
#include <regex>
#include <string>
Le librerie iostream
e string
sono le classiche librerie C++ che ci permettono di avere accesso all’input dell’utente e alla gestione delle stringhe. L’header regex
invece contiene tutte le funzioni che ci permettono di usufruire delle espressioni regolari.
Il nostro programma continua così:
using namespace std;
int main()
{
string input;
regex number("ESPRESSIONE REGOLARE"); // Da definire!
while(true)
{
cout<<"Scrivi un numero: "<<endl;
cin>>input;
//Se la stringa è "q" esci dal programma.
if(input=="q")
break;
if(regex_match(input,number))
cout<<"Numero Valido"<<endl;
else
{
cout<<"Input Invalido"<<endl;
}
}
}
Tutto qui! È un loop estremamente semplice e si basa su due punti:
regex
che prende come parametro l’espressione regolare desiderata (cosa che presto andremo a fare).regex_match
, che prende come parametro una stringa e l’espressione regolare per verificare se la stringa data abbia la stessa struttura definita nella regex
.Non ci resta che definire l’espressione regolare per identificare un numero valido. La sintassi implementata in C++ è la stessa utilizzata dalle espressioni regolari in JavaScript, grep e molti altri famosissimi linguaggi e strumenti di sistema.
Iniziamo da una semplice regex in grado di identificare una cifra fra 0 e 9.
regex number("[[:digit:]]");
Poiché i numeri sono composti da più di una cifra aggiungiamo un +
alla fine. Il segno “più” indica che quello che lo precede può essere ripetuto all’infinito ma almeno una volta.
regex number("[[:digit:]]+");
I numeri, inoltre, possono essere preceduti dal segno “meno” o dal segno “più”. Aggiungiamo anche questa proprietà alla nostra espressione regolare.
regex number("(+|-)?[[:digit:]]+");
Il punto interrogativo (?
) indica che la struttura che lo precede è opzionale. Il simbolo “pipe” (x|y
) invece che andrà bene x
oppure y
. Notate inoltre che poiché il “più” è un simbolo appartenente alle “istruzioni” delle espressioni regolari è necessario precederlo con il doppio backslash .
A questo punto è possibile compilare ed eseguire il programma e cominciare a giocarci su. Per compilarlo con Visual Studio non dovrete fare nulla di particolare (F5), se invece utilizzate Clang il comando è
clang++ -std=c++0x -stdlib=libc++ regex_example.cpp -o regex_example
Un esempio dell’esecuzione dell’applicazione è mostrato nell’immagine seguente:
E se vogliamo identificare anche i numeri decimali? Ci basta modificare la stringa dell’espressione regolare.
regex number("((+|-)?[[:digit:]]+)(.(([[:digit:]]+)?))?");
La stringa è ovviamente più complessa ma la sostanza non cambia.
Oltre alla validazione delle stringhe le espressioni regolari possono essere convenientemente utilizzate per la ricerca di strutture caratteristiche (o pattern) all’interno di un documento. Ad esempio potremmo voler cercare tutti i numeri di telefono o i codici fiscali presenti in una pagina Web. Oppure possiamo voler eliminare tutti i tag HTML da un documento e lasciare solamente il testo.
Per compiere operazioni di questo tipo in modo efficace possiamo utilizzare il comando regex_search
regex_search(input, match_results, regex)
Questa funzione prende in ingresso tre parametri: il primo è la stringa sulla quale operare la ricerca, il secondo è una struttura di tipo match_result, il terzo è l’espressione regolare da ricercare.
Il valore di ritorno sarà true
se il pattern cercato esiste, false
altrimenti.
È giusto spendere qualche parola in più riguardo la struttura in cui viene salvato il risultato della ricerca. La variabile in questione è un istanza della classe template match_result
. Per comodità sono presenti 4 scorciatoie per la sua definizione:
Comando | Descrizione |
---|---|
cmatch | Invoca la creazione di un oggetto match_result per stringhe letterali (ovvero espresse come const char* , come nel C) |
smatch | Invoca la creazione di un oggetto match_result per oggetti stringhe (come istanza della classe string ) |
wcmatch | Invoca la creazione di un oggetto match_result per stringhe letterali di caratteri wide. |
wsmatch | Invoca la creazione di un oggetto match_result per oggetti stringhe di caratteri wide |
Campo1 | Descrizione1 |
Questa struttura non solo immagazzina la prima stringa corrispondente al pattern dato ma ricorda anche le “sotto-espressioni” (le parti racchiuse fra parentesi in un espressione regolare). Quest’ultimo comportamento in particolare ci sarà molto utile nell’ultima parte dell’articolo.
Facciamo anche qui un esempio. Supponiamo di voler estrarre il numero di telefono 06-000023
dalla frase “Spero di riuscire a trovare il numero 06-000023 presente in questa stringa
.” Il numero di telefono è così composto: 2 cifre, un trattino e altre 6 cifre. L’espressione regolare che rappresenta questa struttura è quindi:
regex telephone_number("[[:digit:]]{2}-[[:digit:]]{6}");
Il programma che estrae questo numero sarà semplicemente:
using namespace std;
int main()
{
string input = "Spero di riuscire a trovare il numero 06-000023 presente in questa stringa.";
regex telephone_number("[[:digit:]]{2}-[[:digit:]]{6}");
smatch result;
regex_search(input,result,telephone_number);
cout << result[0].str() << endl;
getchar(); // Se non usate Visual Studio questa riga non serve.
}
Una volta avviato il programma dovreste vedere il numero di telefono correttamente estratto.
L’ultima grande funzionalità delle espressioni regolari è il cosiddetto trova e sostituisci. Anche per questo esiste un semplice comando: regex_replace
regex_replace(input, regex, replacement, option)
In questo caso la funzione prende quattro parametri
Un esempio di questa funzione è dato dal seguente programma:
using namespace std;
int main()
{
string input = "Voglio eliminare 90 tutti i 894 numeri da 39 questa 3513 stringa";
string replacement = "";
regex number("[[:digit:]]+");
string result = regex_replace(input,number,replacement,regex_constants::format_default);
cout << result << endl;
getchar();
}
Questo programma ha l’unico scopo di eliminare tutti i numeri presenti nella frase di input. Ovviamente possiamo usare espressioni regolari arbitrariamente complesse per effettuare compiti meno banali del rimuovere i numeri da una stringa.
Una volta compresi i fondamentali dell’utilizzo delle regex, possiamo addentrarci un po’ e realizzare una applicaizione che svolga un compito più complesso: sfrutteremo le funzioni che abbiamo appena visto (in particolare regex_search
) per creare un programma che converta una stringa formattata in stile Markdown in una stringa che contenga i giusti tag HTML.
Per chi non ne fosse a conoscenza la sintassi Markdown è un metodo molto semplice e diffuso per indicare la formattazione nei documenti di testo. Per non complicare troppo le cose mostreremo l’implementazione di un piccolo sotto-insieme della sintassi Markdown che chiameremo “microMarkDown” e che si limita a indicare parole in grassetto o corsivo:
**parola**
diventa <strong>parola</strong>
.*parola*
diventa <em>parola</em>
.Iniziamo dal principio:
string input = "Abbiamo due **parole** in **grassetto** e una in *corsivo*.";
regex italic("(\*)([[:alpha:]]+)(\*)");
regex bold("(\*\*)([[:alpha:]]+)(\*\*)");
smatch result;
string final_sentence = "";
Innanzitutto inseriamo la stringa di test. Possiamo configurare il nostro programma in modo che tale scritta venga richiesta dall’utente oppure venga letta da un file.
Dopodiché dobbiamo definire le espressioni regolari per il grassetto ed il corsivo. Le espressioni che vedete nell’esempio non sono le migliori possibili e possono essere migliorate (ad esempio permettendo spazi o numeri all’interno della parola da evidenziare) ma per il momento accontentiamoci di questa versione semplice. Fate bene attenzione che ogni espressione regolare è stata suddivisa in tre sotto espressioni (gli asterischi iniziali, il contenuto e gli asterischi che chiudono il grassetto o il corsivo). Questo ci servirà per estrarre il contenuto della frase.
Infine definiamo due variabili. La prima è la classica match_results mentre la seconda è una stringa (inizialmente vuota) che conterrà la stringa elaborata.
/** Gestisci Grassetto **/
while( regex_search(input, result, bold)) {
final_sentence += result.prefix().str() + result.format("$2");
input = result.suffix().str();
}
final_sentence += input;
/** ----- **/
A questo punto cominciamo con la prima elaborazione del grassetto. Attenzione! È importantissimo partire dal grassetto poiché la regex per il corsivo è un sottoinsieme di quella del grassetto. Notate infatti che il pattern descritto nel corsivo (asterisco-parola-asterisco
) è contenuto all’interno della struttura della parola in grassetto (asterisco-asterisco-parola-asterisco-asterisco
). Se facessimo il contrario, invece di trasformare la parola **grassetto**
in <strong>grassetto</strong>
ci ritroveremmo con una stringa *<em>grassetto</em>*
. È quindi importante identificare casi simili quando elaborate sulla stessa frase una serie di espressioni regolari.
Vediamo il codice. In primo luogo c’è un ciclo che continua fintanto ci sono pattern validi nella stringa. All’interno facciamo i seguenti passi:
regex_search
per costruire un primo pezzo della frase elaborata.result.suffix()
” ovvero togliamo da input la parte che abbiamo appena elaborato.Questo piccolo pezzo di codice contiene tre nuovi comandi. I primi due sono le funzioni suffix() e prefix() della classe match_results
. Queste due funzioni ritornano rispettivamente il pezzo di stringa dopo e prima del pattern appena trovato.
Per esempio nella frase “Amo **veramente** le espressioni regolari
“, dopo la ricerca della regex bold
, suffix()
ritornerà “ le espressioni regolari
” mentre prefix()
restituirà “Amo
“.
Il secondo importantissimo comando è format. Questo comando genera una stringa utilizzando i pezzi dell’espressione regolare che abbiamo appena trovato. In particolare:
$0
l’intera stringa trovata. Ad esempio “**veramente**
“.$N
l’N-esima sotto-struttura. Nel caso della nostra espressione regolare $1
conterrà “**
“, $2
conterrà “veramente
” e $3
avrà di nuovo “**
“.Poiché la parola da trasformare in grassetto è identificata dalla seconda sotto-struttura della regex utilizziamo $2
per accedervi. La funzione format
piazza quindi la parola circondata da doppi asterischi in mezzo a <strong>
e </strong>
.
Alla fine del ciclo (ovvero quando non ci sono più stringhe valide nel testo) non ci resta che attaccare ciò che rimane in fondo alla frase.
A questo punto la nostra frase originale sarà diventata: “Abbiamo due <strong>parole</strong> in <strong>grassetto</strong> e una in *corsivo*.
“
Dobbiamo quindi andare ad elaborare la parola in corsivo. Prima di fare ciò dobbiamo “resettare le variabili”.
input = final_sentence;
final_sentence = "";
Primo: la nostra nuova frase di input diventerà la frase parzialmente elaborata. Secondo: svuotiamo la variabile che conterrà la frase elaborata.
/** Gestisci Corsivo **/
while( regex_search(input, result, italic)) {
final_sentence += result.prefix().str() + result.format("<em>$2</em>");
input = result.suffix().str();
}
final_sentence += input;
/** ----- **/
A questo punto il ciclo per il corsivo procede in modo del tutto analogo a quello per il grassetto (con la ovvia differenza di usare il tag <em>
invece del tag <strong>
).
Una volta terminato non ci resta che stampare il risultato (o farne ciò che volete).
cout << final_sentence << endl;
Partendo da questo semplice esempio potete complicare la sintassi del nostro microMarkdown aggiungendo altri elementi. Ad esempio considerando come intestazioni <h1> le righe che circondate con un cancelletto (#
), oppure trasformare una stringa del tipo “(questo è un link)[www.example.com]
” in un corretto link HTML. Possiamo fare questo e molto altro in modo non dissimile da come abbiamo gestito grassetto e corsivo.
Altri Riferimenti
<regex>
su CppReference — Documentazione tecnica sulle espressioni regolari in c++.Se vuoi aggiornamenti su Espressioni regolari in C++11, introduzione inserisci la tua email nel box qui sotto:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
La tua iscrizione è andata a buon fine. Se vuoi ricevere informazioni personalizzate compila anche i seguenti campi opzionali:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
Grazie alle potenzialità del framework JavaScript di Google possiamo integrare al meglio risorse cloud in una Single Page Application: scopriamo […]
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Come creare applicazioni per il Web con PHP e MySQL per il DBMS.
Tutte le principali tecnologie per diventare uno sviluppatore mobile per iOS.
I fondamentali per lo sviluppo di applicazioni multi piattaforma con Java.
Diventare degli esperti in tema di sicurezza delle applicazioni Java.
Usare Raspberry Pi e Arduino per avvicinarsi al mondo dei Maker e dell’IoT.
Le principali guide di HTML.it per diventare un esperto dei database NoSQL.
Ecco come i professionisti creano applicazioni per il Cloud con PHP.
Lo sviluppo professionale di applicazioni in PHP alla portata di tutti.
Come sviluppare applicazioni Web dinamiche con PHP e JavaScript.
Fare gli e-commerce developer con Magento, Prestashop e WooCommerce.
Realizzare applicazioni per il Web utilizzando i framework PHP.
Creare applicazioni PHP e gestire l’ambiente di sviluppo come un pro.
Percorso base per avvicinarsi al web design con un occhio al mobile.
Realizzare siti Web e Web application con WordPress a livello professionale.
Google Colab è una piattaforma per eseguire codice sul Cloud, in forma di Jupyter Notebook: impariamo a conoscere meglio questo potente strumento.
Introduzione a TurboGears, framework per lo sviluppo di applicazioni web sfruttando tutti i vantaggi del linguaggio di programmazione Python.
Guida a Markdown, linguaggio di markup estremamente semplice ed altamente leggibile, molto utilizzato in vari contesti, dai forum alla documentazione.
Telegram non è solo un software di messaggistica istantanea. Oltre a permettere ai suoi utenti l’interscambio di messaggi, esso è infatti personalizzabile in molti modi. Tra questi, è possibile creare dei bot, ovvero dei software in grado di rispondere automaticamente ai messaggi ricevuti dai vari utenti. In questa guida impareremo come implementare un bot per Telegram.