emparejando todos los caracteres en cualquier orden en expresiones regulares

Soy un novato de expresiones regulares, pero comprendo cómo hacer coincidir los caracteres de una consulta de expresiones regulares en orden (ej. [Abc] coincidirá con cualquiera de a, by c. Además, creo que “abc” coincidirá exactamente con abc).

Sin embargo, ¿cómo construyo una consulta de expresiones regulares que coincida con todos los caracteres abc en cualquier orden? Así, por ejemplo, quiero que coincida con “cabina” o “soporte”. Estoy usando Python como mi lenguaje de scripting (no estoy seguro de si esto importa o no).

En Python, no usaría una expresión regular para este propósito, sino un conjunto:

>>> chars = set("abc") >>> chars.issubset("bracket") True >>> chars.issubset("fish") False >>> chars.issubset("bad") False 

Las expresiones regulares son útiles, pero hay situaciones en las que diferentes herramientas son más apropiadas.

Esto se puede hacer con aserciones lookahead:

 ^(?=.*a)(?=.*b)(?=.*c) 

coincide si su cadena contiene al menos una aparición de a , b y c .

Pero como puede ver, eso no es realmente lo que hacen bien las expresiones regulares.

Yo habría hecho:

 if all(char in mystr for char in "abc"): # do something 

Comprobando la velocidad:

 >>> timeit.timeit(stmt='chars.issubset("bracket");chars.issubset("notinhere")', ... setup='chars=set("abc")') 1.3560583674019995 >>> timeit.timeit(stmt='all(char in "bracket" for char in s);all(char in "notinhere" for char in s)', ... setup='s="abc"') 1.4581878714681409 >>> timeit.timeit(stmt='r.match("bracket"); r.match("notinhere")', ... setup='import re; r=re.compile("(?=.*a)(?=.*b)(?=.*c)")') 1.0582279123082117 

Oye, mira, el regex gana! Esto incluso es válido para cadenas de búsqueda más largas:

 >>> timeit.timeit(stmt='chars.issubset("bracketed");chars.issubset("notinhere")', ... setup='chars=set("abcde")') 1.4316702294817105 >>> timeit.timeit(stmt='all(char in "bracketed" for char in s);all(char in "notinhere" for char in s)', ... setup='s="abcde"') 1.6696223364866682 >>> timeit.timeit(stmt='r.match("bracketed"); r.match("notinhere")', ... setup='import re; r=re.compile("(?=.*a)(?=.*b)(?=.*c)(?=.*d)(?:.*e)")') 1.1809254199004044 

Aquí está una comparación temporal de issubset versus las soluciones de expresiones regulares .

 import re def using_lookahead(text): pat=re.compile(r'^(?=.*a)(?=.*b)(?=.*c)') return pat.search(text) def using_set(text): chars=set('abc') return chars.issubset(text) 

Para cadenas pequeñas, issubset puede ser un poco más rápido:

 % python -mtimeit -s'import test' "test.using_set('bracket')" 100000 loops, best of 3: 2.63 usec per loop % python -mtimeit -s'import test' "test.using_lookahead('bracket')" 100000 loops, best of 3: 2.87 usec per loop 

Para cadenas largas, la expresión regular es claramente más rápida:

  • cuando el partido llega tarde:

     % python -mtimeit -s'import test' "test.using_set('o'*1000+'bracket')" 10000 loops, best of 3: 49.7 usec per loop % python -mtimeit -s'import test' "test.using_lookahead('o'*1000+'bracket')" 100000 loops, best of 3: 6.66 usec per loop 
  • cuando el partido llega temprano:

     % python -mtimeit -s'import test' "test.using_set('bracket'+'o'*1000)" 10000 loops, best of 3: 50 usec per loop % python -mtimeit -s'import test' "test.using_lookahead('bracket'+'o'*1000)" 100000 loops, best of 3: 13.9 usec per loop 

(Para responder una pregunta en los comentarios 🙂 r'^(?=.*a)(?=.*b)(?=.*c)' se puede usar para señalar una coincidencia:

 In [40]: pat=re.compile(r'^(?=.*a)(?=.*b)(?=.*c)') In [41]: pat.search('bracket') Out[41]: <_sre.SRE_Match object at 0x9f9a6b0>