Quiero detectar si una palabra está en una oración usando python regex. Además, quiero poder negarlo.

import re
re.match(r'(?=.*\bfoo\b)', 'bar red foo here')

Este código funciona pero no entiendo por qué necesito poner .* allí. También para negarlo, no sé cómo hacerlo. He intentado:

re.match(r'(?!=.*\bfoo\b)', 'bar red foo here')

Pero no funciona. Mi objetivo final es combinarlos así:

re.match(r'(?=.*\bfoo\b)(?!=.*\bbar\b)', 'bar red foo here')
3
max 9 may. 2016 a las 23:48

3 respuestas

La mejor respuesta

Para detectar si una palabra existe en una cadena, necesita una búsqueda positiva :

(?=.*\bfoo\b)

.* es necesario para permitir la búsqueda más allá del inicio de la cadena (re.match ancla la búsqueda al inicio de la cadena).

Para verificar si una cadena no tiene una palabra, use una búsqueda anticipada negativa :

(?!.*\bbar\b)
 ^^^

Entonces, combinándolas:

re.match(r'(?=.*\bfoo\b)(?!.*\bbar\b)', input)

Encontrará una coincidencia en una cadena que contiene una palabra completa foo y no contiene una palabra completa bar.

4
Wiktor Stribiżew 9 may. 2016 a las 20:52

Necesita .* porque re.match() intenta hacer coincidir el patrón con el comienzo de la cadena. Si desea buscar en toda la cadena, use re.search().

Así como puedes hacer if re.search(...):, también puedes hacer if not re.search(...):

1
zondo 9 may. 2016 a las 21:06

Actualizar
Acabo de descubrir que Python re.match () tiene un ancla implícita ^.
En otras palabras, solo coincidirá al comienzo de la cadena,
y extrañamente, a diferencia de Java, no requiere que coincida con la cadena completa.

Sin embargo, tenga en cuenta que la combinación de una búsqueda anticipada positiva y negativa secuencial,
como en la respuesta de Stribnez, puede dar resultados no deseados si no está anclado a
alguna cosa. Ya sea en texto literal o en un ancla BOS ^.

Para uso general, no confíe en el hecho de que (o si), en algún idioma
la función match () implica un ancla BOS ^ (y posiblemente EOS $).
Ponga uno (o ambos) allí en todo momento. De esta manera se puede usar
en search () también. Y es portátil a otros idiomas.

Para ver cuán negativos y positivos, las búsquedas anticipadas en serie pueden causar problemas,
tome esta expresión independiente difícil (?=.*\bfoo\b)(?!.*\bbar\b)

Se puede examinar así:

Como es en serie , ambas afirmaciones deben coincidir al mismo tiempo
posición en la cuerda.

Dada la misma posición en la cadena para ambos, la afirmación negativa
puede satisfacerse cuando encuentra un lugar que aguas abajo no coincide con su contenido.

Suponiendo que no exista un anclaje, este permiso es una apertura aguas arriba
(entre la posición de búsqueda y el literal bar en el ejemplo) para
el contenido no deseado que existe, que aún satisfará lo positivo / negativo
par de afirmación

Ejemplo:
(?=.*\bfoo\b)(?!.*\bbar\b)
coincide
bar red foo

**  Grp 0 -  ( pos 1 , len 0 )  EMPTY 

b<here>ar red foo

Esto muestra que en la posición 1, ambas afirmaciones se cumplen.

Conclusión (es):
1. Utilice siempre anclajes, incluso si están implícitos.
2. Evite usar la función match () de cualquier idioma, use search () en su lugar.

Finalizar actualización


No importa si usa un lookahead positivo o negativo,
Si no utiliza la sintaxis correcta, no funcionará.

Mira esto (?!=.*\bfoo\b)

Esto dice que el siguiente carácter no puede ser un signo igual = seguido de
un número codicioso de caracteres hasta el siguiente foo. Esto no esta permitido.

Por lo tanto, no coincidirá con = ab foo, pero coincidirá con '= (aquí) ab foo'.

El siguiente problema es que si no le das a la afirmación nada para anclar
usará un tope para mover la posición a un lugar entre caracteres
eso lo satisfará.

Las correcciones para la anticipación negativa que está buscando es esta
^(?!.*\bfoo\b)


Como referencia:

(?=..)  Positive lookahead
(?<=..) Positive lookbehind
(?!..)  Negative lookahead
(?<!..) Negative lookbehind   

Y, ellas pueden ser mezcladas y anidadas en cualquier lugar.

1
11 may. 2016 a las 02:59