2016-01-03 9 views
9

Ich möchte alle alternierenden Ziffern in einer Zeichenfolge mit regulären Ausdrücken finden. Eine alternierende Ziffer ist definiert als zwei gleiche Ziffern mit einer Ziffer dazwischen; zum Beispiel enthält 1212 2 Alternationen (121 und 212) und 1111 enthält auch 2 Alternationen (111 und 111). Ich habe den folgenden regulären Ausdruck Code:Alle Vorkommen alternierender Ziffern mit regulären Ausdrücken finden

s = "1212" 
re.findall(r'(\d)(?:\d)(\1)+', s) 

Diese für Zeichenketten wie „121656“ funktioniert, aber nicht „1212“. Dies ist ein Problem mit überlappenden Übereinstimmungen, denke ich. Wie kann ich damit umgehen?

+0

Spezifische Antwort von @vks; Siehe auch Antwort auf ähnliche Frage @ http://StackOverflow.com/a/320478/43774. – rivy

Antwort

7
(?=((\d)\d\2)) 

Verwenden lookahead alle überlappende Spiele zu bekommen. Benutze re.findall und hole das erste Element aus dem Tupel. Sehen Sie sich die Demo:

https://regex101.com/r/fM9lY3/54

+0

Um die Captures seiner Frage zu vergleichen, würde ich '(\ d) (? = (?: \ D) (\ 1))' verwenden. – rivy

+0

@Roy ich denke er will '121 und 212' anstatt' 1 oder 2' – vks

2

Sie ein Look-Ahead können für überlappende Spiele erlauben:

r'(\d)(?=(\d)\1)' 

zu rekonstruieren volle Spiele von dieser:

matches = re.findall(r'(\d)(?=(\d)\1)', s) 
[a + b + a for a, b in matches] 

auch zu vermeiden, dass andere Unicode-Ziffern wie 1 werden verglichen (vorausgesetzt, Sie wollen sie nicht), sollten Sie [0-9] anstelle von \d verwenden.

3

Mit dem regex module Sie müssen nicht einen Trick verwenden überlappten Spiele zu bekommen, da es ein Flag ist, sie zu erhalten:

import regex 
res = [x.group(0) for x in regex.finditer(r'(\d)\d\1', s, overlapped=True)] 

wenn s nur Ziffern enthält, können Sie dies auch tun:

res = [s[i-2:i+1] for i in range(2, len(s)) if s[i]==s[i-2]] 
2

Ein nicht regex Ansatz, wenn Sie Zeichenfolge aus nur Ziffern besteht:

from itertools import islice as isl, izip 

s = "121231132124123" 
out = [a + b + c for a, b, c in zip(isl(s, 0, None), isl(s, 1, None), isl(s, 2, None)) if a == c] 

Ausgabe:

['121', '212', '212'] 

Es ist eigentlich ein schönes Stück schneller als ein regex Ansatz.

Verwandte Themen