Padronanza delle espressioni regolari in Python Un’analisi approfondita della corrispondenza di modelli

Padronanza delle espressioni regolari in Python un'analisi approfondita della corrispondenza di modelli

Python RegEx Demystified: Decifrare l’Arte del Pattern Matching con il Modulo re di Python

Immagine creata dall'autore su Canva

Cos’è Python RegEx o Espressione Regolare?

Le espressioni regolari, spesso abbreviate come regex, sono uno strumento potente per manipolare il testo. Essenzialmente, consistono in una serie di caratteri che stabiliscono un pattern per la ricerca. Questo pattern può essere utilizzato per una vasta gamma di manipolazioni di stringhe, inclusa la corrispondenza di modelli, la sostituzione di testo e la divisione di stringhe.

Storia delle Espressioni Regolari

Fonte Immagine: http://serge.mehl.free.fr/chrono/Kleene.html

Il matematico Stephen Cole Kleene introduce per la prima volta le espressioni regolari negli anni ’50 come notazione per descrivere insiemi regolari o linguaggi regolari.

Oggi, le espressioni regolari sono diventate una competenza essenziale per programmatori, data scientist e professionisti IT.

Importanza e Casistiche di Utilizzo delle Espressioni Regolari di Python

Prima di approfondire come queste espressioni regolari possono essere utilizzate, utilizzando Python, vediamo il differente ambito delle sue applicazioni per motivarci.

  • Validazione dei Dati: Le espressioni regolari possono essere molto utili per convalidare diversi tipi di dati. (indirizzi email, numeri di telefono)
  • Web Scraping: Quando si estraggono dati dalle pagine web, le espressioni regolari possono essere utilizzate per analizzare l’HTML e isolare le informazioni necessarie.
  • Ricerca e Sostituzione: Le espressioni regolari sono efficaci nell’identificare stringhe che rispettano un determinato pattern e sostituirle con alternative. Questa capacità è particolarmente preziosa negli editor di testo, nei database e nella programmazione.
  • Evidenziazione della Sintassi: Un certo numero di editor di testo utilizza le espressioni regolari per l’evidenziazione della sintassi.
  • Elaborazione del Linguaggio Naturale (NLP): Nell’ambito del NLP, le espressioni regolari possono essere utilizzate per attività come la tokenizzazione, la riduzione delle parole alla radice e una serie di altre funzioni di elaborazione del testo.
  • Analisi dei Log: Nell’elaborazione dei file di log, le espressioni regolari sono efficaci nell’estrazione di particolari voci di log o nell’analisi di pattern nel tempo.

Ora spero che siate abbastanza motivati!

Iniziamo con il modulo re, che riguarda le espressioni regolari.

Iniziare con il Modulo re di Python

Grande, iniziamo con i fondamenti del modulo re di Python. Nelle sezioni successive, affronteremo argomenti più avanzati.

Introduzione al Modulo re

Python offre un supporto nativo per le espressioni regolari tramite il modulo re.

Questo modulo è una libreria standard di Python, il che significa che non è necessario installarlo esternamente, verrà fornito con ogni installazione di Python.

Il modulo re contiene varie funzioni e classi per lavorare con le espressioni regolari. Alcune delle funzioni sono utilizzate per cercare corrispondenze di testo, altre per dividere il testo e altre ancora per sostituire il testo.

Include una vasta gamma di funzioni e classi appositamente progettate per gestire le espressioni regolari. Tra queste, alcune funzioni sono designate per la corrispondenza di testo, mentre le altre sono per lo splitting o la sostituzione del testo.

Importare il Modulo re

Come abbiamo già detto, viene fornito con l’installazione, quindi non è necessario preoccuparsi dell’installazione.

È per questo che, per iniziare a utilizzare le espressioni regolari in Python, è necessario importare prima la libreria re. Puoi farlo utilizzando l’istruzione di importazione come segue.

import re

Dopo aver importato la libreria, puoi utilizzare le sue funzionalità come funzioni e classi, fornite dal modulo re.

Iniziamo con un semplice esempio.

Diciamo che vuoi trovare tutte le occorrenze della parola “Python” in una stringa.

Possiamo utilizzare la funzione findall() del modulo re.

Ecco il codice.

import re # Testo di esempio text = "Python è un linguaggio di programmazione fantastico. Python è ampiamente utilizzato in vari settori." # Trova tutte le occorrenze di 'Python' matches = re.findall("Python", text) # Stampa le occorrenze print(matches)

Ecco l’output.

Esistono molte altre funzioni nel modulo re che possiamo utilizzare per creare pattern più complessi.

Ma prima, vediamo le funzioni comuni nel modulo re.

Funzioni comuni nel modulo re

Prima di esprimere i fondamenti di Python RegEx, vediamo prima le funzioni comuni, per comprendere meglio i concetti restanti. Il modulo re include molte diverse funzioni. Utilizzandole, possiamo eseguire diverse operazioni.

Nelle parti seguenti, ne scopriremo alcune.

Immagine creata dall'autore su Canva

a. Funzione re.match()

La funzione re.match() verifica se l’espressione regolare inizia con la stringa specifica o meno.

Se c’è una corrispondenza, la funzione restituisce un oggetto di corrispondenza; altrimenti, restituisce None.

Successivamente, utilizzeremo la funzione re.match(). Qui verificheremo se la stringa text inizia con la parola “Python” o meno. Poi stampiamo il risultato sulla console.

Ecco il codice.

import re pattern = "Python" text = "Python è fantastico." # Verifica se il testo inizia con 'Python' match = re.match(pattern, text) # Stampa il risultato if match: print("Corrispondenza trovata:", match.group()) else: print("Nessuna corrispondenza trovata")

Ecco l’output.

L’output mostra che il pattern “Python” corrisponde all’inizio del testo.

b. Funzione re.search()

In contrasto con re.match(), la funzione re.search() analizza l’intera stringa alla ricerca di una corrispondenza e restituisce un oggetto di corrispondenza se ne viene trovato uno.

Nel codice seguente, utilizziamo la funzione re.search() per cercare la parola “fantastico” ovunque nella stringa text. Se la parola viene trovata, la stampiamo; altrimenti, stampiamo “Nessuna corrispondenza trovata”.

Ecco il codice.

pattern = "fantastico" text = "Python è fantastico." # Cerca il pattern nel testo match = re.search(pattern, text) # Stampa il risultato if match: print("Corrispondenza trovata:", match.group()) else: print("Nessuna corrispondenza trovata")

Ecco l’output.

L’output mostra che il nostro codice trova “fantastico” nel testo fornito.

c. Funzione re.findall()

La funzione re.findall() viene utilizzata per raccogliere tutte le corrispondenze non sovrapposte di un pattern nella stringa. E restituisce queste corrispondenze come una lista di stringhe.

Nell’esempio seguente, utilizziamo la funzione re.findall() per trovare tutte le “a” nella stringa. Le corrispondenze vengono restituite come una lista, che poi stampiamo sulla console.

Ecco il codice.

pattern = "a" text = "Questo è un testo di esempio." # Trova tutte le occorrenze di 'a' nel testo matches = re.findall(pattern, text) # Stampa le occorrenze print(matches)

Ecco l’output.

L’output rappresenta tutte le occorrenze non sovrapposte della lettera “a” trovate nel nostro testo.

d. Funzione re.finditer()

La funzione re.finditer() assomiglia a re.findall(), tuttavia restituisce un iteratore che genera oggetti di corrispondenza.

Nel codice seguente, la funzione re.finditer() viene utilizzata per trovare tutte le occorrenze della lettera “a” nella stringa text. Restituisce un iteratore di oggetti di corrispondenza e stampiamo l’indice e il valore di ogni corrispondenza.

Ecco il codice.

pattern = "a"text = "Questo è un esempio di testo."# Trova tutte le occorrenze di 'a' nel testomatches = re.finditer(pattern, text)# Stampa le corrispondenzefor match in matches:    print(f"Corrispondenza trovata all'indice {match.start()}: {match.group()}")

Ecco l’output.

L’output mostra l’indice del pattern “a” nel testo.

e. Funzione re.sub()

La funzione re.sub() viene utilizzata per effettuare una sostituzione di una stringa con un’altra.

Successivamente, utilizzeremo la funzione re.sub() per sostituire “Python” con “Java”.

Stampiamo quindi la stringa modificata.

Ecco il codice.

pattern = "Python"replacement = "Java"text = "Amo Python. Python è incredibile."# Sostituisci 'Python' con 'Java'new_text = re.sub(pattern, replacement, text)# Stampa il nuovo testoprint(new_text)  # Output: "Amo Java. Java è incredibile."

Ecco l’output.

L’output mostra che possiamo sostituire con successo “Python” con “Java” nel nostro testo.

Nella prossima sezione, scopriremo i modelli di base che possono essere utilizzati nelle espressioni regolari per corrispondere a una varietà di modelli di testo.

Modelli di base nelle espressioni regolari di Python

Iniziamo con i modelli di base.

Le espressioni regolari sono costruite attraverso la combinazione di caratteri letterali, meta-caratteri e quantificatori. Quindi, comprendere questi componenti fondamentali è importante per creare espressioni regolari efficaci.

Iniziamo con i caratteri letterali.

a. Caratteri letterali

I caratteri letterali sono la forma più semplice di corrispondenza di modelli nelle espressioni regolari.

Corrispondono esattamente a se stessi e non hanno un significato speciale.

Ad esempio, l’espressione regolare python corrisponderà esattamente alla stringa python.

import re pattern = "python"text = "Amo programmare in python!" # Trova tutte le occorrenze di 'Python' matches = re.findall(pattern, text) # Stampa le corrispondenze print(matches)

Ecco l’output.

L’output mostra che la nostra funzione re.findall() ha trovato tutte le istanze del pattern “python”.

b. Meta-caratteri

I meta-caratteri come “.”, “^”, “$”. Questi caratteri possono essere molto importanti per manipolare le stringhe. Vediamo.

i. Punto (.)

Il punto . è come una carta Joker. Può rappresentare qualsiasi singolo carattere tranne una nuova riga.

Nel codice seguente, utilizzeremo un pattern di espressione regolare “p.t”.

Ecco il codice.

import re pattern = "p.t"text = "pat, pet, p5t, ma non pt." # Trova tutte le occorrenze di 'Python' matches = re.findall(pattern, text) # Stampa le corrispondenze print(matches)

Ecco l’output.

L’output mostra che il nostro codice ha trovato tutte e tre le istanze di tre caratteri che iniziano con “p” e finiscono con “t”.

ii. Caret (^)

L’accento circonflesso (^) viene utilizzato per verificare se una stringa inizia con un certo carattere.

Vediamo un esempio.

Il codice seguente verifica se il testo inizia con Hello (Match trovato: “match”) o no (Nessun match trovato)

Ecco il codice.

import repattern = "^Hello"text = "Hello, world!"# Usa re.match() perché controlla solo se c'è una corrispondenza all'inizio della stringamatch = re.match(pattern, text)# Output della corrispondenzase match:    print("Match trovato:", match.group())else:    print("Nessun match trovato")

Ecco l’output.

L’output mostra che il nostro codice cattura il modello hello all’inizio del testo.

iii. Dollar Sign ($)

Il simbolo del dollaro $ viene utilizzato per verificare se una stringa termina con un certo carattere.

Il codice seguente verifica se il testo termina con world$ (se sì, stampa “Match trovato: match”) o no (se sì, stampa “Nessun match trovato”)

Ecco il codice.

import repattern = "world$"text = "Hello, world"# Usa re.search() per cercare l'intera stringamatch = re.search(pattern, text)# Output della corrispondenzase match:    print("Match trovato:", match.group())  # Output: Match trovato: worldelse:    print("Nessun match trovato")

Ecco l’output.

L’output mostra che la funzione re.search() ha trovato il testo che termina con la parola “world”.

c. Quantificatori

I quantificatori vengono utilizzati per definire quante volte i caratteri (o il carattere) dovrebbero apparire nel modello che si sta cercando di trovare.

In questa sottosezione, esamineremo esempi sull’asterisco (*), continueremo con il segno più (+), e il punto interrogativo (?), e termineremo con le parentesi graffe ({}).

Iniziamo con un asterisco.

i. Asterisco (*)

L’asterisco (*) in un’espressione regolare indica che il carattere precedente può apparire zero o più volte.

Vediamo il codice. Nel codice seguente, definiamo prima il modello (“py”), quindi utilizzeremo la funzione findall().

Ecco il codice.

import repattern = "py*"text = "p py pyy pyyy pyyyy"matches = re.findall(pattern, text)print(matches)

Ecco l’output.

L’output mostra tutto perché gli asterischi consentono a “y” di apparire zero o più volte.

ii. Plus (+)

Il segno più + corrisponde a una o più ripetizioni del carattere precedente.

Qui usiamo di nuovo la funzione findlall() con il modello py ma questa volta useremo il segno più (+).

Ecco il codice.

import repattern = "py+"text = "p py pyy pyyy pyyyy"matches = re.findall(pattern, text)print(matches)  # Output: ['py', 'pyy', 'pyyy', 'pyyy']

Ecco l’output.

Come possiamo vedere dall’output, il segno più richiede almeno uno o più caratteri “y” dopo la “p”.

iii. Punto interrogativo (?)

Il punto interrogativo ? corrisponde a 0 o 1 ripetizione del carattere precedente. Rende il carattere precedente facoltativo.

Ecco il codice.

import repattern = "py?"text = "p py pyy pyyy pyyyy"matches = re.findall(pattern, text)print(matches)  # Output: ['p', 'py', 'p', 'p', 'p']

Ecco l’output.

Nell’output puoi vedere che corrisponde solo a “p” e “py”, poiché il punto interrogativo permette di apparire “y” una volta o zero volte.

iv. Graffe ({})

Le graffe {} ti permettono di corrispondere a un numero specifico di ripetizioni.

import re
pattern = "py{2,3}"
text = "py, pyy, pyyy, pyyyy"
matches = re.findall(pattern, text)
print(matches)  # Output: ['pyy', 'pyyy', 'pyy']

Ecco l’output.

In questo esempio, il pattern corrisponde a “pyy” e “pyyy”, ma non a “py” o “pyyyy” perché abbiamo specificato che vogliamo corrispondere esattamente a 2 o 3 caratteri “y” dopo “p”.

Caratteri Speciali nelle Espressioni Regolari di Python

I caratteri speciali possono essere utilizzati per costruire pattern più complessi.

Immagine creata dall'autore su Canva

a. Classi di Caratteri

Vediamo prima le classi di caratteri.

Negli esempi seguenti, ne vedremo 3.

Iniziamo con \d, \D.

i. \d, \D

“\d” viene utilizzato per trovare numeri (da 0 a 9), al contrario, “\D” viene utilizzato per trovare elementi che non sono numeri.

Nel codice seguente, “\d” esamina la stringa di testo e recupera i numeri dal testo.

import re
pattern = "\d"
text = "Il mio numero di telefono è 123-456-7890."
matches = re.findall(pattern, text)
print(matches)

Ecco l’output.

L’output mostra che abbiamo trovato tutti i numeri (0-9) nel testo.

ii. \s, \S

“\s” può essere utilizzato per trovare caratteri di spazio, al contrario “\S” può essere utilizzato per trovare tutto ciò che non è spazio.

Nel seguente codice, l’espressione regolare “\s” identifica tutti gli spazi e le tabulazioni nel testo fornito.

Ecco il codice.

import re
pattern = "\s"
text = "Questo è un testo con spazi e\ttabulazioni."
matches = re.findall(pattern, text)
print(matches)  # Output: [' ', ' ', ' ', ' ', ' ', ' ', '\t']

Ecco l’output.

Dagli output possiamo vedere che possiamo identificare tutti gli spazi bianchi.

iii. \w, \W

“\w” può essere utilizzato per trovare parole (lettere, numeri e caratteri di sottolineatura). “\W” è l’opposto di ciò.

Nel codice seguente, “\w” recupera tutte le lettere e i numeri dal testo.

Ecco il codice.

import re
pattern = "\w"
text = "Questo è un esempio con parole e numeri 123!"
matches = re.findall(pattern, text)
print(matches)

Ecco l’output.

b. Classi di caratteri predefinite

Le classi di caratteri predefinite offrono scorciatoie per classi comuni. Ad esempio, “\d” è una classe di caratteri predefinita che rappresenta le cifre.

In questo caso, il pattern “\d” estrae tutte le cifre numeriche dal testo fornito.

import repattern = "\d"text = "L'anno è 2023."# Trova tutte le cifre nel testomatches = re.findall(pattern, text)# Stampa le corrispondenzestampa(matches)

Ecco il risultato.

L’output mostra che il nostro codice ha trovato tutte le istanze della classe di caratteri predefinita “\d” (che rappresenta tutte le cifre) nel testo.

c. Classi di caratteri personalizzate

Le classi di caratteri personalizzate ti consentono di definire il tuo set di caratteri usando le parentesi quadre [].

Nell’esempio qui sotto, la classe di caratteri personalizzata “[aeiou]” viene utilizzata per trovare tutte le lettere vocali nel testo.

Ecco il codice.

import repattern = "[aeiou]"text = "Questo è un esempio di testo."# Trova tutte le vocali nel testomatches = re.findall(pattern, text)# Stampa le corrispondenzestampa(matches)

Ecco il risultato.

L’output mostra tutte le istanze di vocali nel testo come le abbiamo definite.

Possiamo anche utilizzare il simbolo “-” per definire l’intervallo di caratteri.

Ecco il codice.

pattern = "[A-Z]"text = "Questo è un testo di Esempio Con Lettere Maiuscole."# Trova tutte le lettere maiuscole nel testomatches = re.findall(pattern, text)# Stampa le corrispondenzestampa(matches)

Ecco il risultato.

Qui possiamo vedere che l’output è costituito dalle lettere maiuscole nel testo.

Compilazione delle espressioni regolari in Python

Quando si utilizza la stessa espressione regolare più volte in uno script, è conveniente compilarla in un oggetto di pattern prima. Questo risparmia molto tempo perché l’espressione regolare non ha bisogno di essere analizzata nuovamente ad ogni uso.

a. Il metodo compile()

Il metodo re.compile() può essere utilizzato per compilare un pattern di espressione regolare in un oggetto di pattern.

Una volta che abbiamo questo oggetto di pattern, possiamo chiamare i suoi metodi (corrispondenza di testo, ricerca e altre operazioni.)

Ecco il codice.

import re# Compila il pattern dell'espressione regolarepattern = re.compile(r'\d+')  # Corrisponde a una o più cifre# Utilizza l'oggetto di pattern per cercare le corrispondenzetesto = "Ci sono 3 mele e 4 arance."corrispondenze = pattern.findall(testo)# Stampa le corrispondenzestampa(corrispondenze)

Ecco il risultato.

L’output mostra le cifre.

b. Vantaggi della compilazione delle espressioni regolari

Ecco alcuni vantaggi nell’utilizzo delle espressioni regolari:

  • Prestazioni: È più veloce, specialmente se le espressioni regolari verranno utilizzate più volte.
  • Riutilizzabilità: Una volta compilato, lo stesso oggetto di pattern può essere riutilizzato più volte in diverse parti del codice.
  • Leggibilità: Utilizzare un oggetto di pattern può rendere il codice più pulito, specialmente se si utilizzano espressioni regolari complesse.

Ecco un semplice esempio di espressioni regolari compilate:

import re# Compila il pattern dell'espressione regolarepattern = re.compile(r'\d+')  # Corrisponde a una o più cifre# Utilizza l'oggetto di pattern per cercare le corrispondenze in diversi testitesto1 = "Ci sono 3 mele."testo2 = "Ho 15 dollari e 30 centesimi."# Trova le corrispondenze in testo1corrispondenze1 = pattern.findall(testo1)# Trova le corrispondenze in testo2corrispondenze2 = pattern.findall(testo2)# Stampa le corrispondenzestampa(corrispondenze1)

Ecco l’output.

Ora controlliamo il secondo testo.

Ecco il codice.

print(matches2)

Ecco l’output.

Il nostro esempio sopra è piuttosto semplice per farti comprendere l’importanza della riutilizzabilità, delle prestazioni e della leggibilità, specialmente quando il nostro schema di pattern prevede di essere utilizzato ripetutamente.

Esempio pratico: Estrazione numeri di telefono

In questa sezione, testiamo insieme ciò che abbiamo scoperto scrivendo uno script Python per estrarre numeri di telefono dal testo.

Questo è un uso comune delle espressioni regolari, specialmente nel processo di pulizia dei dati.

a. Definire il pattern dell’espressione regolare

I numeri di telefono possono essere in diversi formati, specialmente in diversi paesi, quindi puoi adattare questi numeri in base ai tuoi. Per questo esempio, consideriamo il formato XXX-XXX-XXXX, dove X è una cifra.

Il seguente codice definisce un pattern che corrisponde al formato sopra descritto e lo converte in un’espressione regolare.

Vediamo il codice.

import re# Definisci il pattern dell'espressione regolare per i numeri di telefonopattern_numero_telefono = re.compile(r'\d{3}-\d{3}-\d{4}')

b. Utilizzo del metodo findall()

In questo esempio, utilizzeremo il metodo findall() per estrarre i numeri di telefono che corrispondono al nostro pattern.

Il seguente codice utilizza un pattern di espressione regolare per trovare ed estrarre tutti i

import re# Definisci il pattern dell'espressione regolare per i numeri di telefonopattern_numero_telefono = re.compile(r'\d{3}-\d{3}-\d{4}')# Testo di esempio con numeri di telefonotesto = """John Doe: 123-456-7890Jane Doe: 234-567-8901Ufficio: 555-555-5555"""# Trova tutti i numeri di telefono nel testonumeri_telefono = pattern_numero_telefono.findall(testo)

c. Stampare i risultati

Infine, stampiamo i numeri di telefono estratti sulla console.

Ecco il codice.

# Stampare i numeri di telefonostamp("Numeri di telefono trovati:")for numero_telefono in numeri_telefono:    stampa(numero_telefono)

Ecco l’output.

d. Codice di esempio completo

Ecco lo script Python completo che combina tutti i passaggi precedenti:

import re# Definisci il pattern dell'espressione regolare per i numeri di telefonopattern_numero_telefono = re.compile(r'\d{3}-\d{3}-\d{4}')# Testo di esempio con numeri di telefonotesto = """John Doe: 123-456-7890Jane Doe: 234-567-8901Ufficio: 555-555-5555"""# Trova tutti i numeri di telefono nel testonumeri_telefono = pattern_numero_telefono.findall(testo)# Stampare i numeri di telefonostamp("Numeri di telefono trovati:")for numero_telefono in numeri_telefono:    stampa(numero_telefono)

Ecco l’output.

Best Practices

Mentre continui a lavorare con le espressioni regolari, ecco alcune best practices da tenere a mente:

  • Mantieni la semplicità: La semplicità è la chiave. Si consiglia generalmente di utilizzare un pattern più semplice perché le espressioni regolari possono diventare complicate istantaneamente.
  • Commenta i tuoi pattern: Quando sviluppi espressioni regolari per il tuo progetto, non dimenticare di includere commenti all’interno delle tue note, come abbiamo detto che può essere complicato, ma una volta fatto ciò quando torni indietro, il tuo codice sarà riutilizzabile.
  • Testare accuratamente: Testa il tuo codice più e più volte, perché le espressioni regolari possono talvolta produrre risultati inaspettati a causa della loro complessità, per questo testarle rigorosamente assicurerà che il tuo lavoro funzioni come previsto.
  • Usa stringhe raw: Quando lavori con il testo in Python, a volte utilizzi caratteri speciali che hanno un significato diverso rispetto al solo carattere stesso (come backslash \ o \n per una nuova riga). Per evitare questa confusione, Python ti consente di utilizzare ciò che viene chiamato una “stringa raw”. Rendi una stringa “raw” posizionando la lettera “r” subito prima delle prime virgolette della stringa. Quando fai questo, Python capisce che i backslash in quella stringa devono essere trattati come caratteri normali e non come speciali.

Conclusione

In questa guida, esploreremo il mondo di Python RegEx o Espressioni Regolari. Abbiamo iniziato con le funzioni comuni e i fondamenti per poi passare a concetti più avanzati ed esempi pratici. Ma ricorda, lavorando su progetti reali, che verranno considerati come un esempio per la tua carriera, approfondirai la comprensione di questa conoscenza nella tua mente. Semplicemente facendo ciò, svilupperai competenze e ti risparmierai la ricerca su Google ogni volta che lavori con le espressioni regolari di Python.

Dai un’occhiata a questa guida completa sui concetti avanzati di Python per avere una panoramica di tali concetti.

Spero che tu abbia anche ottenuto informazioni preziose sul Python RegEx leggendo questo articolo.

Grazie per la lettura!

Pubblicato originariamente su https://www.stratascratch.com.