Una expresión regular para que coincida con una subcadena que no está seguida de otra subcadena determinada

115

Necesito una expresión regular que coincida blahfooblahpero noblahfoobarblah

Quiero que coincida solo con foo y todo lo que hay alrededor de foo, siempre que no vaya seguido de barra.

Intenté usar esto: foo.*(?<!bar)que está bastante cerca, pero coincide blahfoobarblah. La mirada negativa detrás debe coincidir con cualquier cosa y no solo con barra.

El lenguaje específico que estoy usando es Clojure, que usa expresiones regulares de Java bajo el capó.

EDITAR: Más específicamente, también necesito que pase, blahfooblahfoobarblahpero no blahfoobarblahblah.

Rayne
fuente
1
¿Intentaste usar foo. * (? <! Bar. *)?
Thibault Falise

Respuestas:

158

Tratar:

/(?!.*bar)(?=.*foo)^(\w+)$/

Pruebas:

blahfooblah            # pass
blahfooblahbarfail     # fail
somethingfoo           # pass
shouldbarfooshouldfail # fail
barfoofail             # fail

Explicación de expresiones regulares

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    bar                      'bar'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    foo                      'foo'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                             more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

Otras expresiones regulares

Si solo desea excluir barcuando es directamente después foo, puede usar

/(?!.*foobar)(?=.*foo)^(\w+)$/

Editar

Actualizó su pregunta para que sea más específica.

/(?=.*foo(?!bar))^(\w+)$/

Nuevas pruebas

fooshouldbarpass               # pass
butnotfoobarfail               # fail
fooshouldpassevenwithfoobar    # pass
nofuuhere                      # fail

Nueva explicación

(?=.*foo(?!bar))asegura que foose encuentre pero no se siga directamentebar

maček
fuente
Esto está muy cerca y es una muy buena respuesta. Sabía que no sería lo suficientemente específico. :( Necesito que pase esto: "blahfoomeowwoof / foobar /" debido al solitario "foo", pero no este blahfoobarmeowwoof Si esto es posible.
Rayne
Como pregunta paralela, ¿cómo se puede hacer coincidir algo como "bot" pero no "botters"?
Rayne
Si. Puedo usar lo que tengo ahora, pero sería más fácil si pudiera emparejar bot pero no botters. Lo siento mucho. No tengo experiencia con las expresiones regulares y me temo que estoy descubriendo lentamente lo que quiero. : p
Rayne
1
@Rayne, esta es la misma pregunta. En su ejemplo anterior, quería hacer coincidir foopero no foobar. Para igualar botpero no botters, usaría /(?=.*bot(?!ters))^(\w+)$/.
maček
Bueno, generalmente apunté a palabras completas. Como dije, estoy confundido acerca de lo que realmente quiero y lo que es realmente posible. Hacerlo así funcionará. Gracias por el tiempo :)
Rayne
55

Para hacer coincidir un fooseguimiento con algo que no comience con bar, intente

foo(?!bar)

Su versión con lookbehind negativo es efectivamente "coincidir con un fooseguido de algo que no termina en bar". Los .*partidos de todos barblah, y los (?<!bar)vuelve a mirar lahy comprueba que no se corresponde bar, que no lo hace, así que todo el patrón de coincidencias.

Stevemegson
fuente
Así que probé esto para una expresión regular que está diseñada para coincidir con la cadena "¿lo hiciste?" Siempre que no esté seguida de "decir". Funciona cuando se diferencia entre "¿dijiste" y "pensaste", por ejemplo, pero solo "lo hiciste" por sí solo no se captura, y debería. ¿Alguna sugerencia?
soosus
2

En su lugar, utilice una mirada negativa hacia el futuro:

\s*(?!\w*(bar)\w*)\w*(foo)\w*\s*

Esto funcionó para mí, espero que ayude. ¡Buena suerte!

Audie
fuente
Regex simple pero efectivo, que también funciona para excluir cadenas repetidas ("foofoo"). ¡Perfecto!
Jonas Byström
1

Escribiste un comentario sugiriendo que te gusta que esto funcione haciendo coincidir todas las palabras en una cadena en lugar de toda la cadena en sí.

En lugar de mezclar todo esto en un comentario, lo publico como una nueva respuesta.

Nueva expresión regular

/(?=\w*foo(?!bar))(\w+)/

Texto de ejemplo

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere ynofuu necesitafoo

Partidos

foowithbar fooevenwithfoobar foohere perofooisokherebar necesitafoo

maček
fuente
0

Su solicitud de coincidencia específica puede coincidir con:

\w+foo(?!bar)\w+

Esto coincidirá blahfooblahfoobarblahpero noblahfoobarblahblah .

El problema con la expresión regular de foo.*(?<!bar)es el .*después foo. Coincide con la mayor cantidad de caracteres, incluidos los personajes posteriores bar.

perro
fuente