Espressioni regolari

Guida base

« Older   Newer »
 
  Share  
.
  1. diosantos
        Like  
     
    .

    User deleted


    INTRODUZIONE

    Le espressioni regolari (regex) sono una manna dal cielo per chi si occupa di programmazione, infatti, tramite queste è possibile descrivere qualsiasi stringa che presenti al suo interno una certa regolarità.

    Senza scendere in formalismi e evitando di parlare di linguaggi regolari o grammatiche regolari, scelgo di portarvi subito un esempio pratico che vi faccia capire l’utilità delle regex.

    Supponiamo di avere una pagina web contenente un form con i seguenti campi:

    * nome
    * cognome
    * email
    * numero di telefono

    Una volta compilato il form ed inviati i dati allo script è importante eseguire un controllo che permetta di verificare la correttezza dei dati stessi.

    Occorre, dunque, definire i vari campi:

    * nome: è formato da una sola parola e può contenere solo lettere dell’alfabeto, sia normali che accentate. Nel nostro caso abbiamo deciso che questo campo non è obbligatorio.
    * cognome: è formato da da una o più parole che possono contenere solo lettere dell’alfabeto (anche accentate) e può in più contenere apici. Questo campo è obbligatorio.
    * email: è formata da 3 parti di cui la prima contenente caratteri alfanumerici, underscore (_) e punti (.) è seguita da una chiocciola (@), dopo di che c’è una seconda parte formata da caratteri alfanumerici e trattini (-), seguita sempre da un punto (.) che è sempre seguito da sole lettere dell’alfabeto di almeno 2 caratteri e al massimo 4. Questo campo è obbligatorio.
    * numero di telefono: formato da 2 parti numeriche separate da un trattino (-). Questo campo è obbligatorio.

    Come vedete è chiaro che i quattro campi posseggono una regolarità che li caratterizza, resta solo da vedere quali sono le espressioni regolari che li individuano. Vi do immediatamente la soluzione del quesito, passando successivamente alla descrizioni delle varie costanti e dei vari operatori utilizzati:

    * nome: [a-zA-Zàòèéùì]*
    * cognome: [a-zA-Zàòèéùì’ ]+
    * email: [a-zA-Z0-9_\.]+@[a-zA-Z0-9-]+\.[a-zA-Z]{0,4}
    * numero di telefono: [0-9]+\-[0-9]+

    ———

    LE CLASSI

    Partiamo descrivendo l’operatore [ ]. Questo metacarattere è formato da una coppia di parentesi quadre al cui interno possono essere inseriti vari caratteri o costanti. Tramite questo metacarattere è possibile individuare una singola occorrenza di uno dei caratteri presenti al suo interno, sia se inseriti come normali caratteri sia se descritti tramite l’uso di costanti: il set di caratteri definito tramite questo operatore prende il nome di classe. Per esempio la classe [a] rappresenta la singola occorrenza del carattere a e permette di verificare che esso sia presente all’interno di una stringa e in quel caso di eseguire alcune operazioni su di esso. Mentre la classe [abcd] rappresenta la singola occorrenza di uno dei quattro caratteri presenti al suo interno e permette di verificare se sono presenti all’interno di una stringa e in tal caso di eseguire operazioni su di essi.

    ———

    L’OPERATORE RANGE

    - invece è un operatore che permette di individuare un range, ad esempio:

    * a-z individua tutte le lettere minuscole
    * A-Z individua tutte le lettere maiuscole
    * 0-9 individua tutte le cifre

    Apparte a questi 3 range classici, se ne possono creare di personalizzati come a-f che individua tutte le lettere minuscole dalla a alla f e che è molto utile per esempio quando si deve individuare numeri esadecimali. La classe [a-fA-F0-9] infatti individua tutti le cifre e le lettere dalla a alla f (minuscole e maiuscole), ovvero tutti i caratteri che possono essere presenti in un numero esadecimale.

    ———

    RIPETIZIONI DI CLASSI

    Adesso passiamo a descrivere gli operatori che si occupano della ripetizione di classi.

    Il primo operatore che analizzeremo è l’asterisco * il quale si occupa di verificare se una classe è ripetuta all’interno di una stringa zero o più volte e di selezionarne tutte le occorrenze consecutive. Per esempio la seguente espressione regolare [a-z]* seleziona all’interno di una stringa tutte le occorrenze consecutive di lettere dell’alfabeto, come mostrato qui di seguito (in grassetto):

    Ho 7 numeri di telefono ma quello di casa è questo: 0004578907

    Dato che questo operatore considera l’insieme vuoto come una soluzione positiva è stato usato per verificare la correttezza del nostro campo NOME, il quale può anche essere vuoto, ma se non lo è dev’essere formato unicamente da una parola. Tutto questo è stato detto tramite la seguente espressione regolare: [a-zA-Zàòèéùì]*

    L’espressione sopra citata individua, dunque, tutte le lettere dell’alfabeto minuscole a-z, tutte le maiuscole A-Z, e le 6 lettere accentate inserite àòèéùì.
    Un operatore molto simile all’asterisco è il più + che esegue la stessa funzione, ma che a differenza del precedente si occupa di verificare se una classe viene ripetuta all’interno di una stringa una o più volte. Per questo motivo lo abbiamo scelto per verificare il campo COGNOME, il quale può contenere una o più parole separate da spazi o apici. Questo è stato descritto tramite questa espressione regolare: [a-zA-Zàòèéùì’ ]+.

    Un altro operatore che individua le ripetizioni consecutive di una classe è formato da 2 parentesi graffe { } al cui interno può essere presente un numero {3} o un range numerico {12,58}. Nel primo caso l’operatore individua tutte le ripetizioni di 3 caratteri che verificano la classe. Nel secondo caso l’operatore individua almeno 12 e al massimo 58 ripetizioni di caratteri che verificano la classe.

    Per esempio [0-9]{3, 4}\-[0-9]{7} individua tutti i numeri telefonici con un prefisso composto da 3 o 4 cifre e un suffisso di esattamente 7 cifre.

    ———

    LO SLASH

    Nell’esempio precedente oltre all’operatore per le ripetizioni definite è stato usato un operatore di cui non vi avevo ancora parlato lo slash \. Questo semplice operatore se anteposto ad un carattere fa in modo se è un operatore che non venga considerato come un carattere, mentre in genere se viene anteposto ad una lettera la trasforma in una costante. Come avevamo visto infatti il trattino - è un operatore utilizzato per indicare un range e quindi se vogliamo utilizzarlo come carattere dobbiamo scriverlo nel seguente modo: \-

    Adesso è totalmente chiara l’espressione regolare che abbiamo utilizzato per verificare l’email:

    [a-zA-Z0-9_\.]+@[a-zA-Z0-9-]+\.[a-zA-Z]{0,4}

    Ed è anche chiara l’espressione che abbiamo utilizzato per verificare il numero di telefono:

    [0-9]+\-[0-9]+

    ———

    PARTICOLARE CARATTERISTICA DEGLI OPERATORI DI RIPETIZIONE

    Una caratteristica degli operatori di ripetizione è quella di selezionare tutto quello che verifica l’espressione, finché possono. Questa caratteristica però potrebbe rivelarsi controproducente in alcuni casi. Per esempio ipotizziamo di voler eliminare da una pagina html tutti i tag; la prima soluzione che può venirci in mente è la seguente espressione regolare:

    <.+>

    Questa regex seleziona una serie consecutiva di caratteri all’interno di una stringa, tali che il primo carattere è < seguiti da una serie di caratteri consecutivi diversi dall’accapo, seguiti da >. Quindi l’espressione regolare sopra descritta nella seguente stringa si comporterà in questo modo:

    <html><head><title>ESPRESSIONI REGOLARI</title></head><body></body></html>

    Praticamente all’interno di una riga seleziona tutto quello che è compreso tra la prima occorrenza del carattere < e l’ultima occorrenza del carattere >.

    Questo non soddisfa la nostra richiesta e dunque è necessario utilizzare uno dei seguenti metodi:

    1. <.+?>
    2. <[^<>]+>

    Il primo rende l’operatore di ripetizione meno forte e fa in modo che si fermi alla prima occorrenza del carattere di chiusura.

    Il secondo, invece, specifica di voler individuare all’interno di una stringa tutte le serie di caratteri che cominciano per < a cui segue qualunque carattere diverso da < e da > a cui segue un >.

    Praticamente all’interno della precedente stringa le due regex appena descritte avranno il seguente effetto:

    <html><head><title>ESPRESSIONI REGOLARI</title></head><body></body></html>

    Verranno, quindi, trovate le 8 occorrenze e sarà possibile operare su di esse in modo da eliminarle.

    ———

    NEGARE UNA CLASSE

    Analizziamo adesso un nuovo problema. Supponiamo di avere un racconto e di voler individuare tutte le frasi presenti al suo interno. Se all’interno di questo racconto il punto viene unicamente utilizzato per finire le frasi, un modo molto semplice di individuarne una è quello di definire una classe negativa, ovvero di negare una classe:

    [^\.]+

    L’operatore ^ se posto subito dopo la prima parentesi quadra di una classe, svolge la funzione di negarla. Quindi nel nostro caso viene individuata la ripetizione consecutiva di tutti quei caratteri che non sono il punto. Praticamente viene individuata una frase.

    ———

    IL PUNTO

    Come avete notato sia ora che nei precedenti esempi, abbiamo sempre slashato tutti i punti, questo perché il punto è una costante, che se inserita all’interno di una espressione regolare equivale a una classe contenente tutti i caratteri tranne l’accapo.

    Un esempio per far capire la funzione del punto può essere il seguente:

    c.s.

    La precedente espressione regolare individua tutte le sequenze di 4 caratteri che cominciano per una c a cui segue qualsiasi carattere tranne l’accapo a cui segue una s a cui segue qualsiasi carattere tranne l’accapo. Possibili combinazioni di carattari che verificano la precedente regex sono le seguenti:

    * casa
    * cosa
    * case
    * cose
    * c%­s9
    * c£sl

    ———

    OPERATORE DI ALTERNANZA

    Un altro operatore molto utile è il pipe | che equivale ad un OR. Per esempio l’espressione regolare giorgio|stuart individua all’interno di una stringa o l’occorrenza della parola giorgio o l’occorrenza della parola stuart, come nell’esempio seguente:

    Sia giorgio che stuart sono due seo famosi, ma giorgio ha un forum, mentre stuart ha una web agency.

    ———

    LE ANCORE

    Un altro problema che potrebbe sorgere è quello di dover modificare uno o più elementi all’interno di un database CSV (comma-separated value), ovvero di un database testuale i cui campi sono separati tramite virgole e i cui records sono divisi tramite accapo. Un esempio pratico può essere il seguente database che rappresenta il guadagno giornaliero tramite adsense generato da tre amici:

    12€,50€,70€
    30€,46€,68€
    15€,52€,73€
    16€,30€,85€

    Se un giorno uno dei tre amici venisse bannato da adsense, i suoi dati non servirebbero più e potrebbe essere necessario eliminarli. Nell’esempio sopra descritto i dati inseriti sono pochi, quindi, una modifica manuale potrebbe essere molto facile da eseguire. Ma se i dati fossero migliaia le espressioni regolari sarebbero una soluzione più veloce. Ammettiamo per esempio che i dati riguardanti l’amico bannato siano quelli inseriti nella terza colonna; una soluzione molto veloce per eliminarla sarebbe quella di eliminare tutte le occorrenze individuate dalla seguente espressione regolare:

    ,[0-9]*€$

    Il carattere $ è una costante che non identifica nessun carattere, bensì identifica una posizione, ovvero il termine di una riga. Quindi la precedente regex trova tutte le serie consecutive di caratteri che cominciano con una virgola a cui seguono alcuni numeri, a cui segue il carattere €, a cui segue il termine di una riga.

    Allo stesso modo è possibile individuare l’inizio di una riga tramite il carattere ^. Questo però va usato con cautela perché come vi ho già spiegato può anche essere usato all’interno di una classe per negare la stessa. Quindi ricordatevi di utilizzarlo sempre al di fuori di una classe. Lo stesso vale per l’operatore $ che se utilizzato all’interno di una classe ha valore di carattere.

    ———

    GRUPPI

    Potremmo, però, voler considerare una serie di caratteri o di classi come un gruppo unico, per poter poi agire su di esso tramite i vari operatori che formano le regex. Per esempio, potremmo voler cercare all’interno di un testo un codice di cui non conosciamo la lunghezza, ma che è composto da 5 numeri seguiti da una lettera a cui seguono 5 numeri a cui segue una lettera, e così via, fino a terminare con un accapo. Per trovare questo codice l’unica soluzione è quella di utilizzare un gruppo. Nel nostro caso il gruppo è formato da una classe che contiene solo numeri e che è ripetuta 5 volte, seguita da una classe che contiene solo lettere. Questo gruppo dev’essere ripetuto almeno una volta e deve terminare con un accapo. Tutto questo si scrive:

    ([0-9]{5}[a-zA-Z])+$

    Un esempio pratico dell’effetto di questa espressione regolare è il seguente:

    Il mio codice segreto è 12345T45345R12343F34567j
    Il codice segreto di pippo è 34526g54638j92725K63723H72829D12345l
    12345T45345R12343F34567j non è il codice di pippo

    ———

    BACKREFERENCES

    Uno dei problemi che potremmo incontrare è quello di voler modificare la posizione di diverse porzioni di testo all’interno di una stringa. Per esempio, ipotizziamo di avere un database csv composto da 5 colonne e 10000 righe che purtroppo contiene un errore: la colonna 2 è stata inserita al posto della colonna 4. Scambiare il posto a queste due colonne potrebbe richiedere ore di lavoro se fatto manualmente, ma le regex ci permetteranno di risolverlo in meno di 5 secondi.

    Infatti, una delle proprietà dei gruppi è quella di memorizzare in una variabile il testo selezionato tramite di essi, in modo da poterlo successivamente utilizzare in fase di sostituizione. Per esempio nel caso precedentemente esposto potremmo voler creare 5 gruppi che selezionano i campi presenti all’interno di una riga del nostro csv. Ammettiamo che il database sia strutturato come segue:

    1,45,589,pippo,luigi
    2,56,79,mario,luigi
    3,57,89,pippo,marco
    ..,..,..,..,..

    Possiamo usare la seguente espressione regolare per selezionare ognuno dei singoli campi all’interno di una riga:

    ([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)$

    Tramite la precedente regex ognuno dei campi verrà memorizzato in una variabile, nella prima ci sarà il primo, nella seconda il secondo e così via. Quindi in generale ci basterà sostituire il testo selezionato con la nuova struttura (1,4,3,2,5) per poter ottenere il risultato desiderato.

    Nasce però un problema. Infatti, ci sono diversi modi per richiamare le variabili.

    htaccess, dreamweaver, PERL richiamano le variabili usando il carattere $. Esempio: $1 per richiamare la prima, $2 per richiamare la seconda. Inoltre $0 per richiamare il match dell’intera regex. Nel precedente esempio avremmo dovuto sostituire la nostra regex con quanto segue:

    $1,$4,$3,$2,$5

    EditPad Pro, PowerGREP richiamano le variabili usando il carattere \. Esempio: \1 per richiamare la prima, \2 per richiamare la seconda. Inoltre \0 per richiamare il match dell’intera regex. Nel precedente esempio avremmo dovuto sostituire la nostra regex con quanto segue:

    \1,\4,\3,\2,\5

    .NET, Javascript, PHP, etc.. richiamano le variabili ognuno con un metodo diverso e si consiglia di leggere le relative guide.

    ATTENZIONE: se usate la ripetizione per ripetere interi gruppi, le variabili si riferiranno ognuna ad un singolo gruppo selezionato e non all’intero gruppo ripetuto. Esempio se usate l’espressione regolare ([0-9]{5}[a-zA-Z])+$ per selezionare i codici su questo testo

    Il mio codice segreto è 12345T45345R12343F34567j

    la variabile 1 corrisponderà solo alla porzione di testo selezionato e non a tutto il codice. Questo avviene perché la ripetizione è esterna alla backreference, quindi, per ovviare questo problema la soluzione è trasformare il gruppo da ripetere in un gruppo senza backreference (in modo che non venga salvato) e impostare una backreference sull’intera ripetizione:

    ((?:[0-9]{5}[a-zA-Z]?)+)$

    Nella regex precedente noterete in particolare la presenza di questa struttura (?: ?) all’interno della quale sono state inserite le 2 classi. Questa struttura è un gruppo senza backreferences; in questo modo abbiamo potuto applicare una ripetizione e memorizzarla internamente. Infatti, adesso nella variabile 1 sarà presente il seguente codice (in grassetto):

    Il mio codice segreto è 12345T45345R12343F34567j

    ———

    IL PUNTO INTERROGATIVO

    Abbiamo appena visto che all’interno dei gruppi il punto interrogativo può essere usato per evitare che venga memorizzato il match, mentre prima avevamo visto che il punto interrogativo può essere usato per limitare l’intrusività delle ripetizioni. Adesso vedremo come esistono molte funzioni per questo semplice carattere.

    Una prima funzione è quella di rendere opzionale un gruppo, come nel seguente esempio:

    pippo( inzaghi)?

    Nella precedente regex il gruppo ( inzaghi) è stato reso opzionale e dunque sarà possibile selezionare sia la semplice occorrenza della parola pippo, sia l’occorrenza della coppia di parole pippo inzaghi.

    Una seconda funzione del punto interrogativo è quella di ancora. Come visto prima esistono operatori come ^ e $ che possono svolgere la funzione di ancore, ovvero individuano all’interno della stringa una posizione. Allo stesso modo il punto interrogativo può essere usato all’interno di un gruppo come ancora, per individuarlo come posizione all’interno del testo. Esempio:

    pippo(?= inzaghi)

    La precedente regex seleziona la parola pippo all’interno del testo solo se è seguita dal gruppo ( inzaghi) che però non verrà selezionato. Esempi:

    Pippo Inzaghi
    Pippo
    Oggi inzaghi ha fatto un goal
    Ieri pippo inzaghi non ha segnato

    Allo stesso modo si può usare il punto interrogativo per individuare l’assenza di una posizione. Per esempio la seguente funzione seleziona la parola pippo solo se non è seguita dal gruppo ( inzaghi):

    pippo(?! inzaghi)

    Esempi:

    Pippo Inzaghi
    Pippo
    Oggi inzaghi ha fatto un goal
    Ieri pippo inzaghi non ha segnato

    Le due proprietà appena descritte funzionano solo quando l’ancora segue il testo (o il gruppo o la classe) da selezionare. Mentre se l’ancora precede il testo da selezionare, vanno usate queste due altre strutture, la prima per verificare la presenza di un ancora, la seconda per verificarne l’assenza:

    (?<=inzaghi) pippo
    (?

    Praticamente viene inserito dopo il punto interrogativo anche il carattere <.

    ———

    FINE?

    Nonostante la smisurata lunghezza di questo post, questa può essere considerata solo una guida base alle espressioni regolari. Il mio scopo è quello di stuzzicare l’interesse dei programmatori, dei seo, dei sem e degli smanettoni verso un argomento che reputo interessantissimo e molto utile. Chi avrà poi voglia di continuare ad approfondirlo troverà su internet milioni di guide sulle espressioni regolari. Ciò che vi posso consigliare è di non buttarvi a capofitto su un argomento che a volte può risultare complesso. Applicate a situazioni pratiche le informazioni che vi ho dato in questa guida e poco per volta comincerete a capire l’importanza di questo magnifico strumento.

    In ogni caso in futuro molto probabilmente realizzerò una guida avanzata, quindi ricordatevi di iscrivervi ai feed!

    ———

    CONSIGLI

    image

    Trovo favoloso EditPad PRO e vi consiglio di scaricarlo: iniziate con la versione demo, così la potrete acquistare solo quando ne capirete i vantaggi. EditPad PRO è un notepad molto evoluto che supporta tra le caratteristiche più interessanti:

    * l’uso dell’espressioni regolari nel Search & Replace
    * un sistema di Search & Replace su più files
    * possibilità di colorare il codice a seconda del tipo di linguaggio di programmazione (o di markup)
     
    .
  2. vonkes
        Like  
     
    .

    User deleted


    https://img.forumfree.net/style_images/23/icon1.gif Diosantos devo farti i miei complimenti più sinceri per il tuo articolo sulle espressioni regolari e a beneficio di chi fosse interessato a questo argomento segnalo questo libro interessantissimo "Espressioni Regolari" di Marco Beri edizioni Apogeo costo € 7,50 collana pocket.
    https://img.forumfree.net/style_images/23/icon9.gif In questo libro viene illustrato come possono essere usate (regex) espressioni regolari in diversi linguaggi di programmazione e precisamente:
    1) Python
    2) Ruby
    3) Perl
    4) Php
    5) JavaScript
    6) Java
    7) .Net
    8) Visual Basic
    Un tester on line di espressioni regolari lo trovate qui Http://regexlib.com/RETester.aspx
    Segnalo anche un altro sito dove potete scaricare e installare sul vs computer http://weitz.de/regex.coach gratuito e gira sia su Windows che sotto Linux, FreeBSD e Mac
    Spero di essere stato di aiuto a quello che Diosantos ha illustrato in merito a questo interessantissimo Argomento.
    vonkes vecchio clipparolo e giovane pythoniano o pythonista
     
    .
1 replies since 15/2/2010, 15:11   3453 views
  Share  
.