2016-02-25 11 views
5

Sto usando python 2.6 e sto cercando di trovare un gruppo di caratteri ripetuti in una stringa, diciamo un gruppo di n, ad es. nnnnnnnABCnnnnnnnnnDEF. In qualsiasi punto della stringa il numero di n può essere variabile.Regex, trova il modello solo nel mezzo della stringa

Se costruisco una regex come questo:

re.findall(r'^(((?i)n)\2{2,})', s),

posso trovare occorrenze di n 's case-insensitive solo all'inizio della stringa, che va bene. Se lo faccio in questo modo:

re.findall(r'(((?i)n)\2{2,}$)', s),

posso rilevare quelli solo alla fine della sequenza. Ma che dire solo nel mezzo?

Inizialmente, ho pensato di utilizzare re.findall(r'(((?i)n)\2{2,})', s) e le due regex precedenti (-ices?) Per controllare la lunghezza dell'elenco restituito e la presenza di n all'inizio o alla fine della stringa ed eseguire test logici , ma è diventato un brutto pasticcio seppur molto rapidamente.

Poi, ho provato re.findall(r'(?!^)(((?i)n)\2{2,})', s), che sembra dovuto escludere l'inizio più che bene, ma (?!$) o (?!\z) alla fine della regex esclude solo l'ultimo n in ABCnnnn. Infine, ho provato re.findall(r'(?!^)(((?i)n)\2{2,})\w+', s) che sembra funzionare a volte, ma ottengo risultati strani agli altri. Mi sembra di aver bisogno di guardare avanti o di guardare indietro, ma non riesco a chiudermi la testa.

+0

Prova [ '(<^?!) ((N) \ 2 {2,})' (

+0

cosa c'è di sbagliato con '((? I) n) \ 1 {2,}' https://regex101.com/r/oT6vZ1/1? –

+0

o '\ B (?

risposta

3

Invece di utilizzare una regex complicata per rifiutare la corrispondenza dei caratteri iniziali e finali n. Come un approccio più divinatorio è possibile strip() la stringa poi trovare tutta la sequenza di n s utilizzando re.findall() e una semplice espressione regolare:

>>> s = "nnnABCnnnnDEFnnnnnGHInnnnnn" 
>>> import re 
>>> 
>>> re.findall(r'n{2,}', s.strip('n'), re.I) 
['nnnn', 'nnnnn'] 

Nota: re.I è Ignora caso bandiera che rende l'espressione regolare il motore combacia con caratteri maiuscoli e minuscoli.

+0

'n' è una sequenza di caratteri. Dovrai "re.subarli", credo. –

+0

@ WiktorStribiżew Non importa, 'str.strip()' rimuoverà tutte le occorrenze iniziali e finali dell'argomento passato. – Kasramvd

+0

@ WiktorStribiżew: sembra che 'n' sia un personaggio, vedere gli ultimi commenti. –

1

NOTA: Questa soluzione presuppone n può essere una sequenza di alcuni caratteri. Per alternative più efficienti quando n è solo 1 carattere, vedi altre risposte qui.

È possibile utilizzare

(?<!^)(?<!n)((n)\2{2,})(?!$)(?!n) 

Vedere la regex demo

L'espressione regolare corrisponderà ripetuto consecutiva n s (caso ignorando può essere raggiunto con re.I bandiera) che non sono all'inizio ((?<!^)) o fine ((?!$)) della stringa e non prima ((?!n)) o dopo ((?<!n)) un altro n.

Il (?<!^)(?<!n) è una sequenza di 2 lookbehinds: (?<!^) significa non consumano il modello successivo se preceduto con l'inizio della stringa. Lo sguardo negativo (?<!n) significa non consumare il modello successivo se preceduto con n. I lookaheads negativi (?!$) e (?!n) hanno significati simili: (?!$) fallisce una corrispondenza se dopo la posizione corrente si verifica alla fine della stringa e (?!n) fallirà una corrispondenza se n verifica dopo la posizione corrente nella stringa (cioè, subito dopo corrispondenza tutte consecutivi n s .. le condizioni Lookaround devono essere tutti soddisfatti, questo è il motivo per cui abbiamo solo le partite più interne

Vedere IDEONE demo:

import re 
p = re.compile(r'(?<!^)(?<!n)((n)\2{2,})(?!$)(?!n)', re.IGNORECASE) 
s = "nnnnnnnABCnnnnnNnnnnDEFnNn" 
print([x.group() for x in p.finditer(s)]) 
2

Dal momento che "n" è un personaggio (e non un criterio posto), si può semplicemente utilizzare:

re.findall(r'(?<=[^n])nn+(?=[^n])(?i)', s) 

o meglio:

re.findall(r'n(?<=[^n]n)n+(?=[^n])(?i)', s) 
Problemi correlati