L'espressione regolare Python trova tutte le corrispondenze sovrapposte?


98

Sto cercando di trovare ogni serie di 10 cifre di numeri all'interno di una serie più ampia di numeri usando re in Python 2.6.

Sono facilmente in grado di non afferrare partite sovrapposte, ma voglio tutte le partite della serie numerica. Per esempio.

in "123456789123456789"

Dovrei ottenere il seguente elenco:

[1234567891,2345678912,3456789123,4567891234,5678912345,6789123456,7891234567,8912345678,9123456789]

Ho trovato riferimenti a un "lookahead", ma gli esempi che ho visto mostrano solo coppie di numeri piuttosto che raggruppamenti più grandi e non sono stato in grado di convertirli oltre le due cifre.


6
Le soluzioni presentate non funzioneranno quando le corrispondenze sovrapposte iniziano nello stesso punto, ad esempio, la corrispondenza di "a | ab | abc" contro "abcd" restituirà solo un risultato. Esiste una soluzione che non implichi la chiamata a match () più volte, tenendo traccia manualmente del confine 'end'?
Vítor De Araújo

@ VítorDeAraújo: le espressioni regolari sovrapposte come (a|ab|abc)possono generalmente essere riscritte come non sovrapposte con gruppi di cattura annidati, ad esempio (a(b(c)?)?)?, dove ignoriamo tutti tranne il gruppo di cattura più esterno (cioè quello più a sinistra) quando decomprimiamo una corrispondenza; certamente questo è un po 'doloroso e meno leggibile. Questa sarà anche una regex più performante da abbinare.
smci

Risposte:


175

Usa un gruppo di cattura all'interno di un lookahead. Il lookahead acquisisce il testo che ti interessa, ma la corrispondenza effettiva è tecnicamente la sottostringa di larghezza zero prima del lookahead, quindi le corrispondenze sono tecnicamente non sovrapposte:

import re 
s = "123456789123456789"
matches = re.finditer(r'(?=(\d{10}))',s)
results = [int(match.group(1)) for match in matches]
# results: 
# [1234567891,
#  2345678912,
#  3456789123,
#  4567891234,
#  5678912345,
#  6789123456,
#  7891234567,
#  8912345678,
#  9123456789]

2
La mia risposta è almeno 2 volte più veloce di questa. Ma questa soluzione è complicata, la raccomando.
eyquem

16
Spiegazione = invece di cercare il modello (10 cifre), cerca qualsiasi cosa SEGUITO DAL modello. Quindi trova la posizione 0 della stringa, la posizione 1 della stringa e così via. Quindi afferra il gruppo (1) - il modello di corrispondenza e ne fa un elenco. MOLTO bello.
Tal Weiss

Non avevo idea che potessi utilizzare gruppi di corrispondenza all'interno di lookahead, che normalmente non dovrebbero essere inclusi in una corrispondenza (e i sottogruppi abbinati in effetti non appaiono la corrispondenza completa). Poiché questa tecnica sembra ancora funzionare in Python 3.4, immagino che sia considerata una funzionalità piuttosto che un bug.
JAB

10
Mi sono iscritto a StackOverflow, ho risposto alle domande e mi sono fatto una reputazione solo per poter votare questa risposta. Sono bloccato con Python 2.4 per ora, quindi non posso usare le funzioni regex più avanzate di Python 3, e questo è solo il tipo di bizzarro trucco che stavo cercando.
TheSoundDefense

2
Potresti aggiungere più spiegazioni al codice. Non è il modo migliore secondo Stack Overflow, per avere solo codice in una risposta. Aiuterà sicuramente le persone.
Akshay Hazari

77

Puoi anche provare a utilizzare il modulo di terze partiregex (not re), che supporta le corrispondenze sovrapposte.

>>> import regex as re
>>> s = "123456789123456789"
>>> matches = re.findall(r'\d{10}', s, overlapped=True)
>>> for match in matches: print match
...
1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789

17

Mi piacciono le espressioni regolari, ma qui non sono necessarie.

Semplicemente

s =  "123456789123456789"

n = 10
li = [ s[i:i+n] for i in xrange(len(s)-n+1) ]
print '\n'.join(li)

risultato

1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789

10
Le espressioni regolari non sono necessarie qui perché stai applicando la conoscenza speciale "all'interno di una serie più ampia di numeri", quindi sai già che ogni posizione 0 <= i < len(s)-n+1è garantita come l'inizio di una partita a 10 cifre. Inoltre immagino che il tuo codice potrebbe essere accelerato, sarebbe interessante code-golf per la velocità.
smci
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.