Ricerca…


introduzione

Python rende disponibili le espressioni regolari attraverso il modulo re .

Le espressioni regolari sono combinazioni di caratteri che vengono interpretate come regole per la corrispondenza delle sottostringhe. Ad esempio, l'espressione 'amount\D+\d+' corrisponderà qualsiasi stringa composta dalla parola amount più un numero intero, separati da uno o più non cifre, ad esempio: amount=100 , amount is 3 , amount is equal to: 33 , ecc.

Sintassi

  • Espressioni regolari dirette

  • re.match (pattern, stringa, flag = 0) # Out: combina pattern all'inizio della stringa o None

  • re.search (pattern, string, flag = 0) # Out: combina pattern all'interno di string o None

  • re.findall (pattern, stringa, flag = 0) # Out: lista di tutte le corrispondenze di pattern in stringa o []

  • re.finditer (pattern, string, flag = 0) # Out: uguale a re.findall, ma restituisce l'oggetto iteratore

  • re.sub (modello, sostituzione, stringa, flag = 0) # Out: stringa con sostituzione (stringa o funzione) al posto del modello

  • Espressioni regolari precompilate

  • precompiled_pattern = re.compile (pattern, flag = 0)

  • precompiled_pattern.match (stringa) # Out: corrisponde all'inizio della stringa o None

  • precompiled_pattern.search (stringa) # Out: corrisponde ovunque in stringa o None

  • precompiled_pattern.findall (stringa) # Out: elenco di tutte le sottostringhe corrispondenti

  • precompiled_pattern.sub (stringa / modello / funzione, stringa) # Out: stringa sostituita

Corrisponde all'inizio di una stringa

Il primo argomento di re.match() è l'espressione regolare, il secondo è la stringa da abbinare:

import re

pattern = r"123"
string = "123zzb"

re.match(pattern, string)
# Out: <_sre.SRE_Match object; span=(0, 3), match='123'>

match = re.match(pattern, string)

match.group()
# Out: '123'

Si può notare che la variabile pattern è una stringa preceduta da r , che indica che la stringa è un letterale stringa raw .

Un letterale stringa raw ha una sintassi leggermente diversa rispetto a un letterale stringa, ovvero una barra rovesciata \ in una stringa raw significa letteralmente "solo un backslash" e non è necessario raddoppiare i backlashes per evitare "sequenze di escape" come newlines ( \n ) , schede ( \t ), backspaces ( \ ), form-feeds ( \r ) e così via. In normali stringhe di stringa, ogni backslash deve essere raddoppiata per evitare di essere presa come l'inizio di una sequenza di escape.

Quindi, r"\n" è una stringa di 2 caratteri: \ e n . Anche i pattern Regex usano i backslash, ad esempio \d riferisce a qualsiasi carattere numerico. È possibile evitare di dover eseguire il doppio escape delle stringhe ( "\\d" ) utilizzando stringhe non elaborate ( r"\d" ).

Per esempio:

string = "\\t123zzb" # here the backslash is escaped, so there's no tab, just '\' and 't'
pattern = "\\t123"   # this will match \t (escaping the backslash) followed by 123
re.match(pattern, string).group()   # no match
re.match(pattern, "\t123zzb").group()  # matches '\t123'

pattern = r"\\t123"  
re.match(pattern, string).group()   # matches '\\t123'

La corrispondenza viene eseguita solo dall'inizio della stringa. Se vuoi abbinare ovunque usa re.search :

match = re.match(r"(123)", "a123zzb")

match is None
# Out: True

match = re.search(r"(123)", "a123zzb")

match.group()
# Out: '123'

Ricerca

pattern = r"(your base)"
sentence = "All your base are belong to us."

match = re.search(pattern, sentence)
match.group(1)
# Out: 'your base'

match = re.search(r"(belong.*)", sentence)
match.group(1)
# Out: 'belong to us.'

La ricerca viene eseguita ovunque nella stringa, diversamente da re.match . Puoi anche usare re.findall .

Puoi anche cercare all'inizio della stringa (usa ^ ),

match = re.search(r"^123", "123zzb")
match.group(0)
# Out: '123'

match = re.search(r"^123", "a123zzb")
match is None
# Out: True

alla fine della stringa (usa $ ),

match = re.search(r"123$", "zzb123")
match.group(0)
# Out: '123'

match = re.search(r"123$", "123zzb")
match is None
# Out: True

o entrambi (usa sia ^ che $ ):

match = re.search(r"^123$", "123")
match.group(0)
# Out: '123'

Raggruppamento

Il raggruppamento è fatto con parentesi. Calling group() restituisce una stringa formata dai sottogruppi parentesi corrispondenti.

match.group() # Group without argument returns the entire match found
# Out: '123'
match.group(0) # Specifying 0 gives the same result as specifying no argument
# Out: '123'

Gli argomenti possono anche essere forniti a group() per recuperare un determinato sottogruppo.

Dai documenti :

Se c'è un singolo argomento, il risultato è una singola stringa; se ci sono più argomenti, il risultato è una tupla con un elemento per argomento.

Calling groups() d'altra parte, restituisce una lista di tuple contenenti i sottogruppi.

sentence = "This is a phone number 672-123-456-9910"
pattern = r".*(phone).*?([\d-]+)"

match = re.match(pattern, sentence)

match.groups()   # The entire match as a list of tuples of the paranthesized subgroups
# Out: ('phone', '672-123-456-9910')

m.group()        # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'

m.group(0)       # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'

m.group(1)       # The first parenthesized subgroup.
# Out: 'phone'

m.group(2)       # The second parenthesized subgroup.
# Out: '672-123-456-9910'

m.group(1, 2)    # Multiple arguments give us a tuple.
# Out: ('phone', '672-123-456-9910')

Gruppi con nome

match = re.search(r'My name is (?P<name>[A-Za-z ]+)', 'My name is John Smith')
match.group('name')
# Out: 'John Smith'

match.group(1)
# Out: 'John Smith'

Crea un gruppo di cattura che può essere referenziato per nome e per indice.

Gruppi non catturanti

Usando (?:) crea un gruppo, ma il gruppo non viene catturato. Ciò significa che puoi usarlo come gruppo, ma non inquinerà il tuo "spazio di gruppo".

re.match(r'(\d+)(\+(\d+))?', '11+22').groups()
# Out: ('11', '+22', '22')

re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups()
# Out: ('11', '22')

Questo esempio corrisponde a 11+22 o 11 , ma non 11+ . Questo perché il segno + e il secondo termine sono raggruppati. D'altra parte, il segno + non viene catturato.

Escaping Special Characters

I caratteri speciali (come le parentesi [ e ] sotto) della classe di caratteri non sono letteralmente abbinati:

match = re.search(r'[b]', 'a[b]c')
match.group()
# Out: 'b'

Sfuggendo ai caratteri speciali, possono essere abbinati letteralmente:

match = re.search(r'\[b\]', 'a[b]c')
match.group()
# Out: '[b]'

La funzione re.escape() può essere utilizzata per fare questo per te:

re.escape('a[b]c')
# Out: 'a\\[b\\]c'
match = re.search(re.escape('a[b]c'), 'a[b]c')
match.group()
# Out: 'a[b]c'

La funzione re.escape() sfugge a tutti i caratteri speciali, quindi è utile se si sta scrivendo un'espressione regolare basata sull'input dell'utente:

username = 'A.C.'  # suppose this came from the user
re.findall(r'Hi {}!'.format(username), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!', 'Hi ABCD!']
re.findall(r'Hi {}!'.format(re.escape(username)), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!']

Sostituzione

Le sostituzioni possono essere fatte su stringhe usando re.sub .

Sostituire le stringhe

re.sub(r"t[0-9][0-9]", "foo", "my name t13 is t44 what t99 ever t44")
# Out: 'my name foo is foo what foo ever foo'

Utilizzando riferimenti di gruppo

Sostituzioni con un numero limitato di gruppi possono essere effettuate come segue:

re.sub(r"t([0-9])([0-9])", r"t\2\1", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'

Tuttavia, se si crea un ID di gruppo come "10", questo non funziona : \10 viene letto come 'ID numero 1 seguito da 0'. Quindi devi essere più specifico e usare la notazione \g<i> :

re.sub(r"t([0-9])([0-9])", r"t\g<2>\g<1>", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'

Utilizzando una funzione di sostituzione

items = ["zero", "one", "two"]
re.sub(r"a\[([0-3])\]", lambda match: items[int(match.group(1))], "Items: a[0], a[1], something, a[2]")
# Out: 'Items: zero, one, something, two'

Trova tutte le corrispondenze non sovrapposte

re.findall(r"[0-9]{2,3}", "some 1 text 12 is 945 here 4445588899")
# Out: ['12', '945', '444', '558', '889']

Notare che il r prima di "[0-9]{2,3}" dice a python di interpretare la stringa as-is; come una stringa "grezza".

Puoi anche usare re.finditer() che funziona allo stesso modo di re.findall() ma restituisce un iteratore con oggetti SRE_Match invece di un elenco di stringhe:

results = re.finditer(r"([0-9]{2,3})", "some 1 text 12 is 945 here 4445588899")
print(results)
# Out: <callable-iterator object at 0x105245890>
for result in results:
     print(result.group(0))
''' Out:
12
945
444
558
889
'''

Modelli precompilati

import re

precompiled_pattern = re.compile(r"(\d+)")
matches = precompiled_pattern.search("The answer is 41!")
matches.group(1)
# Out: 41

matches = precompiled_pattern.search("Or was it 42?")
matches.group(1)
# Out: 42

La compilazione di un modello consente di riutilizzarlo in seguito in un programma. Tuttavia, si noti che Python memorizza nella cache le espressioni utilizzate di recente ( documenti , risposta SO ), quindi "i programmi che utilizzano solo alcune espressioni regolari alla volta non devono preoccuparsi di compilare le espressioni regolari" .

import re

precompiled_pattern = re.compile(r"(.*\d+)")
matches = precompiled_pattern.match("The answer is 41!")
print(matches.group(1))
# Out: The answer is 41

matches = precompiled_pattern.match("Or was it 42?")
print(matches.group(1))
# Out: Or was it 42

Può essere usato con re.match ().

Verifica dei caratteri consentiti

Se vuoi verificare che una stringa contenga solo un determinato set di caratteri, in questo caso az, AZ e 0-9, puoi farlo in questo modo,

import re

def is_allowed(string):
    characherRegex = re.compile(r'[^a-zA-Z0-9.]')
    string = characherRegex.search(string)
    return not bool(string)
    
print (is_allowed("abyzABYZ0099")) 
# Out: 'True'

print (is_allowed("#*@#$%^")) 
# Out: 'False'

È anche possibile adattare la linea di espressione da [^a-zA-Z0-9.] [^a-z0-9.] , Per non consentire le lettere maiuscole, ad esempio.

Credito parziale: http://stackoverflow.com/a/1325265/2697955

Dividere una stringa usando le espressioni regolari

Puoi anche usare espressioni regolari per dividere una stringa. Per esempio,

import re
data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74')
print( data )
# Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']

bandiere

Per alcuni casi speciali abbiamo bisogno di cambiare il comportamento dell'Espressione Regolare, questo viene fatto usando le bandiere. Le bandiere possono essere impostate in due modi, attraverso la parola chiave flags o direttamente nell'espressione.

Parola chiave delle bandiere

Di seguito un esempio per re.search ma funziona per la maggior parte delle funzioni nel modulo re .

m = re.search("b", "ABC")  
m is None
# Out: True

m = re.search("b", "ABC", flags=re.IGNORECASE)
m.group()
# Out: 'B'

m = re.search("a.b", "A\nBC", flags=re.IGNORECASE) 
m is None
# Out: True

m = re.search("a.b", "A\nBC", flags=re.IGNORECASE|re.DOTALL) 
m.group()
# Out: 'A\nB'

Bandiere comuni

Bandiera breve descrizione
re.IGNORECASE , re.I Fa in modo che il modello ignori il caso
re.DOTALL , re.S Rende . abbinare tutto compreso a capo
re.MULTILINE , re.M Rende ^ corrisponde all'inizio di una linea e $ alla fine di una linea
re.DEBUG Attiva le informazioni di debug

Per l'elenco completo di tutte le flag disponibili, controlla i documenti

Bandiere in linea

Dai documenti :

(?iLmsux) (Una o più lettere dal set 'i', 'L', 'm', 's', 'u', 'x'.)

Il gruppo corrisponde alla stringa vuota; le lettere impostano i flag corrispondenti: re.I (ignora il caso), re.L (dipendente dalla locale), re.M (multi-line), re.S (punto corrisponde a tutti), re.U (dipendente da Unicode), e re.X (dettagliato), per l'intera espressione regolare. Ciò è utile se si desidera includere i flag come parte dell'espressione regolare, invece di passare un argomento flag alla funzione re.compile ().

Si noti che il flag (? X) cambia il modo in cui l'espressione viene analizzata. Dovrebbe essere usato prima nella stringa di espressione o dopo uno o più caratteri di spaziatura. Se ci sono caratteri non spazi bianchi prima del flag, i risultati non sono definiti.

Iterare le partite usando `re.finditer`

È possibile utilizzare re.finditer per re.finditer tutte le corrispondenze in una stringa. Questo ti dà (in confronto a re.findall informazioni extra, come ad esempio informazioni sulla posizione della partita nella stringa (indici):

import re
text = 'You can try to find an ant in this string'
pattern = 'an?\w' # find 'an' either with or without a following word character

for match in re.finditer(pattern, text):
    # Start index of match (integer)
    sStart = match.start()

    # Final index of match (integer)
    sEnd = match.end()

    # Complete match (string)
    sGroup = match.group()

    # Print match
    print('Match "{}" found at: [{},{}]'.format(sGroup, sStart,sEnd))

Risultato:

Match "an" found at: [5,7]
Match "an" found at: [20,22]
Match "ant" found at: [23,26]

Abbina un'espressione solo in posizioni specifiche

Spesso vuoi abbinare un'espressione solo in luoghi specifici (lasciandoli intatti in altri, cioè). Considera la seguente frase:

An apple a day keeps the doctor away (I eat an apple everyday).

Qui la "mela" si verifica due volte che può essere risolta con i cosiddetti verbi di controllo backtracking che sono supportati dal modulo regex più recente. L'idea è:

forget_this | or this | and this as well | (but keep this)

Con il nostro esempio di mela, questo sarebbe:

import regex as re
string = "An apple a day keeps the doctor away (I eat an apple everyday)."
rx = re.compile(r'''
    \([^()]*\) (*SKIP)(*FAIL)  # match anything in parentheses and "throw it away"
    |                          # or
    apple                      # match an apple
    ''', re.VERBOSE)
apples = rx.findall(string)
print(apples)
# only one

Questo corrisponde a "mela" solo quando può essere trovato al di fuori delle parentesi.


Ecco come funziona:
  • Mentre guarda da sinistra a destra , il motore regex consuma tutto a sinistra, il (*SKIP) agisce come una "affermazione sempre vera". Successivamente, fallisce correttamente (*FAIL) e backtrack.
  • Ora arriva al punto di (*SKIP) da destra a sinistra (aka mentre backtracking) dove è vietato andare ulteriormente a sinistra. Invece, al motore viene detto di gettare via qualsiasi cosa a sinistra e saltare al punto in cui è stato invocato il (*SKIP) .


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow