Come usare il modulo di espressione regolare Python re (match, search, sub, ecc.)

Attività commerciale

Per eseguire l'elaborazione delle espressioni regolari in Python, usiamo il modulo re dalla libreria standard. Permette di estrarre, sostituire e dividere stringhe usando modelli di espressioni regolari.

In questa sezione, spiegheremo prima le funzioni e i metodi del modulo re.

  • Compilazione di modelli di espressioni regolari:compile()
  • oggetto di corrispondenza
  • Controlla se l'inizio della stringa corrisponde, estrae:match()
  • Controlla le partite non limitate all'inizio:search()
  • Controlla se l'intera stringa corrisponde:fullmatch()
  • Ottieni una lista di tutte le parti corrispondenti:findall()
  • Ottiene tutte le parti corrispondenti come iteratore:finditer()
  • Sostituire la parte corrispondente:sub(),subn()
  • Dividere le stringhe con modelli di espressioni regolari:split()

Dopo di che, spiegherò i meta caratteri (caratteri speciali) e le sequenze speciali delle espressioni regolari che possono essere usate nel modulo re. Fondamentalmente, è la sintassi standard delle espressioni regolari, ma fate attenzione all'impostazione dei flag (specialmente re.ASCII).

  • Metacaratteri delle espressioni regolari, sequenze speciali e avvertenze in Python
  • Impostare la bandiera
    • Limitato ai caratteri ASCII:re.ASCII
    • Non sensibile alle maiuscole e alle minuscole:re.IGNORECASE
    • Abbina l'inizio e la fine di ogni riga:re.MULTILINE
    • Specificare più bandiere
  • Partite avide e non avide

Compilare il modello di espressione regolare: compile()

Ci sono due modi per eseguire l'elaborazione delle espressioni regolari nel modulo re.

Eseguire con la funzione

Il primo è una funzione.re.match(),re.sub()Funzioni come queste sono disponibili per eseguire estrazioni, sostituzioni e altri processi utilizzando modelli di espressioni regolari.

I dettagli delle funzioni saranno descritti più avanti, ma in tutte, il primo argomento è la stringa del modello di espressione regolare, seguita dalla stringa da elaborare e così via. Per esempio, in re.sub(), che esegue la sostituzione, il secondo argomento è la stringa di sostituzione, e il terzo argomento è la stringa da elaborare.

import re

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Notate che [a-z] nel modello di espressione regolare in questo esempio significa qualsiasi carattere dalla a alla z (cioè l'alfabeto minuscolo), e + significa ripetere il modello precedente (in questo caso [a-z]) una o più volte. Il [a-z]+ corrisponde a qualsiasi stringa che ripete uno o più caratteri alfabetici minuscoli.

. è un metacarattere (un carattere con un significato speciale) e deve essere evaso con un backslash.

Poiché le stringhe di pattern di espressioni regolari spesso usano molte backslash, è conveniente usare stringhe grezze come nell'esempio.

Viene eseguito in un metodo di un oggetto pattern di espressione regolare

Il secondo modo di trattare le espressioni regolari nel modulo re è il metodo dell'oggetto pattern di espressione regolare.

Usando re.compile(), potete compilare una stringa di pattern di espressione regolare per creare un oggetto pattern di espressione regolare.

p = re.compile(r'([a-z]+)@([a-z]+)\.com')

print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')

print(type(p))
# <class 're.Pattern'>

re.match(),re.sub()Per esempio, lo stesso processo di queste funzioni può essere eseguito come metodi match(),sub() di oggetti espressione regolare.

m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Tutte le funzioni re.xxx() descritte di seguito sono anche fornite come metodi dell'oggetto espressione regolare.

Se state ripetendo un processo che usa lo stesso schema, è più efficiente generare un oggetto espressione regolare con re.compile() e usarlo in giro.

Nel seguente codice di esempio, la funzione è usata senza compilare per comodità, ma se volete usare lo stesso modello ripetutamente, si raccomanda di compilarlo in anticipo e di eseguirlo come metodo di un oggetto espressione regolare.

oggetto di corrispondenza

match(), search(), ecc. restituiscono un oggetto match.

s = 'aaa@xxx.com'

m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(m))
# <class 're.Match'>

La stringa abbinata e la posizione sono ottenute utilizzando i seguenti metodi dell'oggetto match.

  • Ottieni la posizione della partita:start(),end(),span()
  • Ottieni la stringa abbinata:group()
  • Ottieni la stringa per ogni gruppo:groups()
print(m.start())
# 0

print(m.end())
# 11

print(m.span())
# (0, 11)

print(m.group())
# aaa@xxx.com

Se racchiudete una parte di un pattern di espressione regolare in una stringa con le parentesi(), la parte verrà processata come un gruppo. In questo caso, la stringa della parte che corrisponde ad ogni gruppo in groups() può essere ottenuta come tupla.

m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.groups())
# ('aaa', 'xxx', 'com')

Controllare se l'inizio di una stringa corrisponde, estrarre: match()

match() restituisce un oggetto match se l'inizio della stringa corrisponde al pattern.

Come menzionato sopra, l'oggetto match può essere usato per estrarre la sottostringa abbinata, o semplicemente per controllare se è stata fatta una corrispondenza.

match() controlla solo l'inizio. Se non c'è nessuna stringa corrispondente all'inizio, restituisce None.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None

Controlla le corrispondenze non limitate all'inizio, estrarre: search()

Come match(), restituisce un oggetto match se corrisponde.

Se ci sono più parti corrispondenti, verrà restituita solo la prima parte corrispondente.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Se volete ottenere tutte le parti corrispondenti, usate findall() o finditer() come descritto sotto.

Controlla se l'intera stringa corrisponde: fullmatch()

Per controllare se l'intera stringa corrisponde al modello di espressione regolare, usare fullmatch(). Questo è utile, per esempio, per controllare se una stringa è valida come indirizzo email o no.

Se l'intera stringa corrisponde, viene restituito un oggetto match.

s = 'aaa@xxx.com'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Se ci sono parti non corrispondenti (solo corrispondenze parziali o nessuna corrispondenza), viene restituito None.

s = '!!!aaa@xxx.com!!!'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None

Il fullmatch() è stato aggiunto in Python 3.4. Se volete fare lo stesso nelle versioni precedenti, usate match() e un meta carattere corrispondente $ alla fine. Se l'intera stringa dall'inizio alla fine non corrisponde, restituisce None.

s = '!!!aaa@xxx.com!!!'

m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None

Ottenere un elenco di tutte le parti corrispondenti: findall()

findall() restituisce una lista di tutte le sottostringhe corrispondenti. Notate che gli elementi della lista non sono oggetti match ma stringhe.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']

Il numero di parti abbinate può essere controllato usando la funzione built-in len(), che restituisce il numero di elementi nella lista.

print(len(result))
# 3

Raggruppare con parentesi() in un modello di espressione regolare restituisce una lista di tuple i cui elementi sono le stringhe di ogni gruppo. Questo è equivalente a groups() nell'oggetto match.

result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]

Le parentesi di gruppo () possono essere annidate, quindi se volete ottenere anche l'intera partita, basta racchiudere l'intera partita tra parentesi ().

result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]

Se non viene trovata alcuna corrispondenza, viene restituita una tupla vuota.

result = re.findall('[0-9]+', s)
print(result)
# []

Ottenere tutte le parti corrispondenti come un iteratore: finditer()

finditer() restituisce tutte le parti corrispondenti come un iteratore. Gli elementi non sono stringhe come findall(), ma oggetti di corrispondenza, in modo da poter ottenere la posizione (indice) delle parti corrispondenti.

L'iteratore stesso non può essere stampato con print() per ottenere il suo contenuto. Se usate la funzione built-in next() o l'istruzione for, potete ottenere i contenuti uno per uno.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>

print(type(result))
# <class 'callable_iterator'>

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

Può anche essere convertito in una lista con list().

l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]

print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(l[0]))
# <class 're.Match'>

print(l[0].span())
# (0, 11)

Se volete ottenere la posizione di tutte le parti corrispondenti, la notazione list comprehension è più conveniente di list().

print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]

L'iteratore estrae gli elementi in ordine. Notate che se cercate di estrarre altri elementi dopo aver raggiunto la fine, rimarrete con niente.

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

print(list(result))
# []

Sostituire le parti corrispondenti: sub(), subn()

Usando sub(), potete sostituire la parte abbinata con un'altra stringa. La stringa sostituita verrà restituita.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

print(type(result))
# <class 'str'>

Quando si raggruppa con parentesi(), la stringa abbinata può essere usata nella stringa sostituita.

Per impostazione predefinita, è supportato quanto segue: Si noti che per le stringhe normali che non sono stringhe grezze, un backslash deve essere elencato prima del backslash per evitare il backslash.

\1La prima parentesi
\2La seconda parentesi
\3La terza parentesi
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

?P<xxx>
Se date un nome al gruppo scrivendolo all'inizio delle parentesi del modello di espressione regolare, potete specificarlo usando il nome invece del numero, come mostrato qui sotto.
\g<xxx>

result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

L'argomento count specifica il numero massimo di sostituzioni. Solo il conteggio dal lato sinistro sarà sostituito.

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net

subn() restituisce una tupla della stringa sostituita (la stessa del valore di ritorno di sub()) e il numero di parti sostituite (il numero che corrisponde al modello).

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)

Il metodo per specificare gli argomenti è lo stesso di sub(). Potete usare la parte raggruppata da parentesi, o specificare il numero di argomenti.

result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)

Dividere le stringhe con modelli di espressioni regolari: split()

split() divide la stringa nella parte che corrisponde al modello e la restituisce come lista.

Si noti che la prima e l'ultima corrispondenza conterranno stringhe vuote all'inizio e alla fine della lista risultante.

s = '111aaa222bbb333'

result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']

result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']

L'argomento maxsplit specifica il numero massimo di suddivisioni (pezzi). Solo il conteggio dal lato sinistro sarà spaccato.

result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']

Metacaratteri delle espressioni regolari, sequenze speciali e avvertenze in Python

I principali meta caratteri delle espressioni regolari (caratteri speciali) e le sequenze speciali che possono essere usati nel modulo Python 3 re sono i seguenti

metacaratterecontenuto
.Qualsiasi singolo carattere diverso da una linea nuova (inclusa una linea nuova con il flag DOTALL)
^L'inizio della stringa (corrisponde anche all'inizio di ogni linea con il flag MULTILINE)
$La fine della stringa (corrisponde anche alla fine di ogni linea con il flag MULTILINE)
*Ripetere lo schema precedente più di 0 volte
+Ripetere lo schema precedente almeno una volta.
?Ripetere lo schema precedente 0 o 1 volta
{m}Ripetere lo schema precedente m volte
{m, n}L'ultimo modello.m~nripetere
[]Un insieme di caratteri[]Corrisponde a uno qualsiasi di questi caratteri
|OA|BCorrisponde al modello A o B
sequenza specialecontenuto
\dNumeri decimali Unicode (limitati ai numeri ASCII dal flag ASCII)
\D\dCioè il contrario di questo.
\sCaratteri di spazio bianco Unicode (limitati ai caratteri di spazio bianco ASCII dal flag ASCII)
\S\sCioè il contrario di questo.
\wCaratteri di parola Unicode e sottolineature (limitati ai caratteri alfanumerici ASCII e alle sottolineature da flag ASCII)
\W\wCioè il contrario di questo.

Non tutti sono elencati in questa tabella. Vedere la documentazione ufficiale per una lista completa.

Notate anche che alcuni significati sono diversi in Python 2.

Impostare la bandiera

Come mostrato nella tabella qui sopra, alcuni meta caratteri e sequenze speciali cambiano il loro modo a seconda della bandiera.

Qui sono coperte solo le bandiere principali. Vedere la documentazione ufficiale per il resto.

Limitato ai caratteri ASCII: re.ASCII

\wQuesto corrisponderà anche a kanji a doppio byte, caratteri alfanumerici, ecc. per impostazione predefinita per le stringhe Python 3. Non è equivalente alla seguente perché non è un'espressione regolare standard.[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None

Se specificate re.ASCII per i flag dell'argomento in ogni funzione, o aggiungete il seguente flag inline all'inizio della stringa di pattern dell'espressione regolare, essa corrisponderà solo ai caratteri ASCII (non corrisponderà al giapponese a doppio byte, ai caratteri alfanumerici, ecc.)
(?a)
In questo caso, i due seguenti sono equivalenti.
\w=[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None

m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None

Lo stesso vale quando si compila con re.compile(). Usare l'argomento flags o inline flags.

p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

ASCII è anche disponibile come forma breve re. A. È possibile utilizzare entrambi.

print(re.ASCII is re.A)
# True

\W, l'opposto di \W, è anche influenzato da re.ASCII e dai flag inline.

m = re.match(r'\W+', '漢字ABC123')
print(m)
# None

m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

Come con \w, i due seguenti corrispondono sia ai caratteri a singolo byte che a doppio byte per impostazione predefinita, ma sono limitati ai caratteri a singolo byte se vengono specificati i flag re.ASCII o inline.

  • Abbinare i numeri\d
  • Corrisponde a uno spazio vuoto\s
  • Corrisponde ai non-numeri\D
  • Corrisponde a qualsiasi non-spazio.\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None

m = re.match(r'\s+', ' ')  # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>

m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None

Non sensibile alle maiuscole e alle minuscole:re.IGNORECASE

Per impostazione predefinita, è sensibile alle maiuscole e alle minuscole. Per corrispondere a entrambi, è necessario includere sia lettere maiuscole che minuscole nel modello.

re.IGNORECASESe questo è specificato, corrisponderà in modo indifferente alle maiuscole e alle minuscole. Equivalente al flag i nelle espressioni regolari standard.

m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

Puoi usare meno di o uguale a.

  • bandiera inline(?i)
  • abbreviazionere.I

Abbina l'inizio e la fine di ogni riga:re.MULTILINE

^I meta caratteri di questa espressione regolare corrispondono all'inizio della stringa.

Per impostazione predefinita, viene abbinato solo l'inizio dell'intera stringa, ma il seguente abbinerà anche l'inizio di ogni riga. Equivalente al flag m nelle espressioni regolari standard.
re.MULTILINE

s = '''aaa-xxx
bbb-yyy
ccc-zzz'''

print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz

result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']

result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']

result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']

$Corrisponde alla fine della stringa. Per impostazione predefinita, viene abbinata solo la fine dell'intera stringa.
re.MULTILINESe si specifica questo, corrisponderà anche alla fine di ogni riga.

result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']

result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']

Puoi usare meno di o uguale a.

  • bandiera inline(?m)
  • abbreviazionere.M

Specificare più bandiere

|Se vuoi abilitare più flag allo stesso tempo, usa questo. Nel caso di flag in linea, ogni carattere deve essere seguito da una lettera come mostrato di seguito.
(?am)

s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''

print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz

result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']

result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']

result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']

Partite avide e non avide

Questo è un problema generale con le espressioni regolari, non solo un problema con Python, ma ne scriverò perché tende a mettermi nei guai.

Per impostazione predefinita, il seguente è un greedy match, che corrisponde alla stringa più lunga possibile.

  • *
  • +
  • ?
s = 'aaa@xxx.com, bbb@yyy.com'

m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>

print(m.group())
# aaa@xxx.com, bbb@yyy.com

Il ? dopo di esso risulterà in una corrispondenza minima non grezza, che corrisponde alla stringa più corta possibile.

  • *?
  • +?
  • ??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.group())
# aaa@xxx.com

Si noti che l'abbinamento avido predefinito può corrispondere a stringhe inaspettate.