2011-07-11 13 views
12

Przepraszam za tytuł, nie mogłem wymyślić czystej odpowiedzi na moje pytanie.Dopasowanie do wzorca Python. Dopasuj c [dowolną liczbę kolejnych a, b lub c, b, c lub a itd.] T '

W języku Python chciałbym dopasować wyrażenie "c [niektóre rzeczy] t", gdzie [kilka rzeczy] może być dowolną liczbą kolejnych a, b lub c w dowolnej kolejności.

Na przykład, te prace: 'ct', 'kot', 'cbbt', 'caaabbct', 'cbbccaat'

ale te nie: 'cbcbbaat', 'caaccbabbt'

Edit: a, b, a c znajdują się w odległości Na przykład, ale naprawdę chciałbym móc rozszerzyć to na więcej liter. Jestem zainteresowany rozwiązaniami regex i non-regex.

+0

Z większości odpowiedzi wynika, że ​​jedynym sposobem kodowania jest ręczne skonfigurowanie wszystkich przypadków. Czy to prawda? Byłoby to bardzo trudne, gdybym chciał dodać jeszcze dwie litery. Myślę, że będzie to 120 przypadków. – Usagi

+0

"teraz masz dwa problemy"? – geoffspear

+0

@Wooble - Nie, chcę, żeby to rozwiązanie było rozszerzalne. Całkowicie ręczne/bezpośrednie podejście wymagałoby wielu pisania. – Usagi

Odpowiedz

6

Nie wiem, jak przywiązany jesteś do regex, ale tutaj jest rozwiązanie, używając innej metody:

from itertools import groupby 

words = ['ct', 'cat', 'cbbt', 'caaabbct', 'cbbccaat', 'cbcbbaat', 'caaccbabbt'] 
for w in words: 
    match = False 
    if w.startswith('c') and w.endswith('t'): 
     temp = w[1:-1] 
     s = set(temp) 
     match = s <= set('abc') and len(s) == len(list(groupby(temp))) 
    print w, "matches" if match else "doesn't match" 

Łańcuch pasuje czy zestaw środkowych znaków jest podzbiorem set('abc'), a liczba grup zwróconych przez groupby() jest taka sama, jak liczba elementów w zestawie.

+0

Jestem zainteresowany tym, jak porównuje się efektywność. Nie jestem koniecznie związany z regex. – Usagi

+0

Bardzo ładne, a także łatwo rozszerzalne! Napisałem odpowiedź bez odpowiedzi, ale twoja jest o wiele lepsza, więc po prostu podaję ci upomnienie zamiast zamieszczać moje. –

+0

+1: łatwiejsze do odczytania niż rozwiązanie regex. –

0

Nie znam silnika regex Pythona, ale brzmi to tak, jakbyś chciał bezpośrednio wypisać 6 różnych możliwych zamówień.

/c(a*b*c*|a*c*b*|b*a*c*|b*c*a*|c*a*b*|c*b*a*)t/ 
+0

Czy istnieje inny sposób? Jeśli chciałbym dodać na przykład d i e, musiałbym ręcznie wpisać 120 przypadków. – Usagi

+1

@Usagi No. Coś bardziej skomplikowanego i naprawdę powinieneś pozbyć się wyrażeń regularnych i przeanalizować go ręcznie. –

+1

@Usagi: Możesz napisać funkcję, która generuje ciąg regex dość łatwo, aby uniknąć pisania ręcznego. – trutheality

3

wierzę, trzeba wyraźnie kodować wszystkie możliwe permutacje a s, b s oraz c s:

c(a*b*c*|b*a*c*|b*c*a*|c*b*a*|c*a*b*|a*c*b*)t 

pamiętać, że jest to bardzo nieefektywne kwerendy, które mogą wycofać się wiele.

+0

To robi? Wydaje mi się, że najwyżej cały ciąg mógł zostać zanalizowany 6 razy, zanim się nie powiodło. Nie widzę żadnego ekspotencjalnego wybuchu typowego dla problematycznych wyrażeń regularnych ... – 6502

0

AFAIK nie ma "compact" sposób to zrobić ...

c(a*(b*c*|c*b*)|b*(a*c*|c*a*)|c*(a*b*|b*a*))t 
14

Nie gruntownie przetestowany, ale myślę, że to powinno działać:

import re 

words = ['ct', 'cat', 'cbbt', 'caaabbct', 'cbbccaat', 'cbcbbaat', 'caaccbabbt'] 
pat = re.compile(r'^c(?:([abc])\1*(?!.*\1))*t$') 
for w in words: 
    print w, "matches" if pat.match(w) else "doesn't match" 

#ct matches 
#cat matches 
#cbbt matches 
#caaabbct matches 
#cbbccaat matches 
#cbcbbaat doesn't match 
#caaccbabbt doesn't match 

Dopasowuje przebiegi a, b lub c (to jest część ([abc])\1*), podczas gdy ujemny poprzednik (?!.*\1) upewnia się, że po uruchomieniu nie ma żadnej innej instancji tej postaci.

(edit: naprawiono literówkę w wyjaśnieniu)

+0

Działa jak urok :) – Usagi

Powiązane problemy