2011-07-11 4 views
12

Perdón por el título, no pude encontrar una manera clara de hacer mi pregunta.Coincidencia de patrones Python. Coincide con 'c [cualquier cantidad de a's, b's o c's o b's consecutivos, c's o a's, etc.] t'

En Python me gustaría hacer coincidir una expresión 'c [algo] t', donde [algunas cosas] podría ser cualquier cantidad de a, b, o c consecutivas y en cualquier orden.

Por ejemplo, estos trabajos: 'ct', 'gato', 'CBBT', 'caaabbct', 'cbbccaat'

pero éstos no lo hacen: 'cbcbbaat', 'caaccbabbt'

editar: a de, B, y C son sólo de una n ejemplo, pero me gustaría poder ampliar esto a más letras. Estoy interesado en soluciones regex y no regex.

+0

Parece de la mayoría de las respuestas que la única forma de codificar esto es configurar manualmente todos los casos. ¿Es esto cierto? Esto sería muy difícil si quisiera agregar dos letras más. Creo que serían 120 casos. – Usagi

+0

"ahora tienes dos problemas"? – geoffspear

+0

@Wooble - No, solo quiero que la solución sea extensible. El enfoque completamente manual/directo requeriría mucha escritura. – Usagi

Respuesta

6
No

seguro de cómo apegado estés de expresiones regulares, pero aquí es una solución utilizando un método diferente:

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" 

La cadena coincide si un conjunto de los caracteres del medio es un subconjunto de set('abc') y el número de grupos devueltos por groupby() es el mismo que el número de elementos en el conjunto.

+0

Me interesa cómo se comparan las eficiencias. No estoy necesariamente apegado a Regex. – Usagi

+0

¡Muy agradable, y también fácilmente extensible! Escribí una respuesta no-regular, pero la tuya es mucho mejor, así que solo te estoy dando un voto positivo en lugar de publicar el mío. –

+0

+1: más fácil de leer que la solución de expresiones regulares. –

0

No conozco el motor de expresiones regulares de Python, pero parece que lo que desea es escribir directamente los 6 posibles pedidos diferentes.

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

¿Hay alguna otra manera? Si quisiera agregar dye, por ejemplo, tendría que escribir 120 casos manualmente. – Usagi

+1

@Usagi No. Algo más complicado y realmente debería deshacerse de las expresiones regulares y analizarlas manualmente en su lugar. –

+1

@Usagi: Puede escribir una función que genere la serie de expresiones regulares con bastante facilidad para evitar el tipeo manual. – trutheality

3

Creo que usted necesita para codificar explícitamente todas las permutaciones posibles de a s, s b y c s:

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

Tenga en cuenta que se trata de una consulta extremadamente ineficiente que puede retroceder mucho.

+0

¿Lo hace? Me parece que a lo sumo todo el hilo podría ser analizado 6 veces antes de fallar. No veo ninguna explosión exponencial típica de las expresiones regulares problemáticas ... – 6502

0

yo sepa no hay forma "compacta" de hacer esto ...

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

No se ha probado a fondo, pero creo que esto debería funcionar:

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 

Esto coincide con carreras de a, o bc (esa es la parte ([abc])\1*), mientras que el lookahead negativo (?!.*\1) se asegura de que no haya ninguna otra instancia de ese carácter después de la ejecución.

(edit: fija un error tipográfico en la explicación)

+0

Funciona como un encanto :) – Usagi

Cuestiones relacionadas