¿Sintaxis de expresión regular para "no coincide con nada"?

82

Tengo un motor de plantillas de Python que usa mucho regexp. Utiliza la concatenación como:

re.compile( regexp1 + "|" + regexp2 + "*|" + regexp3 + "+" )

Puedo modificar las subcadenas individuales (regexp1, regexp2, etc.).

¿Hay alguna expresión pequeña y ligera que no coincida con nada, que pueda usar dentro de una plantilla en la que no quiero coincidencias? Desafortunadamente, a veces se agrega '+' o '*' al átomo de expresiones regulares, por lo que no puedo usar una cadena vacía, lo que generará un error de "nada que repetir".

grigoryvp
fuente
3
¿Podría redactarse mejor el título como "Expresión regular para no coincidir con nada"? No coincidir con nada implica una coincidencia exitosa de una cadena vacía.
BamaPookie

Respuestas:

123

Esto no debería coincidir con nada:

re.compile('$^')

Entonces, si reemplaza regexp1, regexp2 y regexp3 con '$ ^', será imposible encontrar una coincidencia. A menos que esté utilizando el modo multilínea.


Después de algunas pruebas encontré una mejor solución.

re.compile('a^')

Es imposible de igualar y fallará antes que la solución anterior. Puede reemplazar a con cualquier otro carácter y siempre será imposible hacer coincidir

Nadia Alramli
fuente
¿Eso no coincidirá con nada con seguridad y es liviano para que el motor regexp lo procese? (no quiero que mis stub regexps coman mucha CPU)
grigoryvp
@Ojo del infierno. Debe ser liviano. Esto intentará hacer coincidir un final de línea seguido de un inicio de línea. Lo que es imposible en una línea.
Nadia Alramli
1
Pero es posible con varias líneas, por supuesto (dependiendo de si la bandera está habilitada): para una solución que funcione si la bandera está habilitada o no, vea mi respuesta.
Peter Boughton
16
La expresión regular "$ ^" coincide con la cadena vacía, al menos en algunas implementaciones. El segundo es mejor.
Roman Starkov
@romkyns El segundo no coincide con la cadena vacía en mi llamada a PyQt4 QtCore.QRegExp. Tan malo, ya que seguramente habría sido más ligero de ejecutar.
Joël
43

(?!)siempre debe fallar en coincidir. Es la anticipación negativa de ancho cero. Si lo que está entre paréntesis coincide, toda la coincidencia falla. Dado que no tiene nada, fallará la coincidencia por cualquier cosa (incluido nada).

Chas. Owens
fuente
4
Bien, yo también iba a publicar esto. Esta es la mejor manera, si su idioma admite búsquedas anticipadas. Asimismo (? =) Coincide con todas las cadenas.
Brian Carper
16

Para hacer coincidir una cadena vacía, incluso en modo multilínea, puede usar \A\Z, entonces:

re.compile('\A\Z|\A\Z*|\A\Z+')

La diferencia es que \Ay \Zson el inicio y el final de la cadena , mientras que ^y $estos pueden coincidir con el inicio / final de las líneas , por lo que $^|$^*|$^+podrían coincidir con una cadena que contiene nuevas líneas (si la bandera está habilitada).

Y para no coincidir con nada (incluso una cadena vacía), simplemente intente encontrar contenido antes del inicio de la cadena, por ejemplo:

re.compile('.\A|.\A*|.\A+')

Dado que ningún carácter puede aparecer antes de \ A (por definición), esto siempre fallará en coincidir.

Peter Boughton
fuente
El tuyo se ve mejor que el mío, ya que supongo que saldría más rápido que usar el final de línea.
ShuggyCoUk
Peter, ¿usas \ z (minúsculas) mientras que mi guía de bolsillo de Python me dice que la afirmación del final de la cadena es \ Z (mayúsculas)?
ThomasH
ThomasH, ambos son finales de cadena, pero la versión en mayúsculas permite una nueva línea al final mientras que la minúscula no.
Peter Boughton
Mh, interesante, no encuentro esto documentado en ninguna parte. Además, re.search ("boo \ z", "fooboo") no devuelve un objeto coincidente, mientras que re.search ("boo \ Z", "fooboo) sí. Más bien, re.search (" boo \ z "," foobooz ") , lo que indica el hecho de que '\ z' se interpreta simplemente como 'z', ¿verdad? (Esto está en Python 2.6).
ThomasH
Ah, lo siento, pensé que Python era PCRE, pero resulta que hay algunas diferencias, y esta es una de ellas. (Ver 'Anchors' en regular-expressions.info/refflavors.html )
Peter Boughton
4

'.{0}'¿ Quizás ?

Steef
fuente
1

Puede usar
\z..
Este es el final absoluto de la cadena, seguido de dos de cualquier cosa

Si +o *está tachado al final, esto todavía funciona negándose a coincidir con nada

ShuggyCoUk
fuente
¿Por qué dos de cualquier cosa? El IIRC \zno permite el seguimiento de nuevas líneas, a diferencia \Z, ¿no será suficiente con una? O esta es una defensa extraña contra *(¿por qué te estás protegiendo contra eso?)
mpen
0

O use un poco de comprensión de la lista para eliminar las entradas de expresiones regulares inútiles y únase para juntarlas todas. Algo como:

re.compile('|'.join([x for x in [regexp1, regexp2, ...] if x != None]))

Sin embargo, asegúrese de agregar algunos comentarios junto a esa línea de código :-)

Mike Miller
fuente