2009-08-06 40 views
443

Sé que puedo negar el grupo de caracteres como en [^bar] pero necesito una expresión regular donde la negación se aplica a la palabra específica, por lo que en mi ejemplo ¿cómo puedo negar un "bar" real y no "any chars in bar"?¿Cómo negar palabra específica en expresiones regulares?

+1

Posible duplicado de [¿Expresión regular para hacer coincidir la línea que no contiene una palabra?] (Http: // stackoverflow.com/questions/406230/regular-expression-to-match-line-that-doesnt-contain-a-word) –

Respuesta

480

Una gran manera de hacer esto es utilizar negative lookahead:

^(?!.*bar).*$ 
+7

Esto lo dice todo (probablemente hubiera comenzado con (? !bar) y construido). No veo por qué otras personas lo están haciendo tan complicado. – Beta

+24

Desafortunadamente, esto no funciona con todos los idiomas. – JAB

+4

carácter de inicio de línea al principio hace un trabajo bastante bueno. – dhblah

31

Usted podría utilizar un negative look-ahead or look-behind:

^(?!.*?bar).* 
^(.(?<!bar))*?$ 

O utilice solo lo básico:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$ 

Estos todo el partido nada que no contiene bar.

+0

Qué idiomas no son compatibles con los aspectos negativos (negativos) y/o (negativos) con los look-aheads en regex ? – JAB

+4

Creo que el objetivo es que, mirando su patrón, no está para nada claro que todo lo que hace es rechazar la palabra "barra". –

+0

@Bryan: Y, de hecho, no rechaza la palabra "barra". Simplemente rechaza "b" cuando es seguido por "ar". – JAB

57

A menos que el rendimiento es de suma importancia, a menudo es más fácil sólo para ejecutar sus resultados a través de una segunda pasada, omitiendo los que coinciden con las palabras que desea anular.

expresiones

regulares por lo general significa que estás haciendo secuencias de comandos o algún tipo de tarea de bajo rendimiento de todos modos, por lo que encontrar una solución que es fácil de leer, fácil de entender y fácil de mantener.

40

La siguiente expresión regular hará lo que usted desee (siempre y lookbehinds como negativos y los símbolos de anticipación son compatibles), igualando las cosas bien; el único problema es que coincide con los caracteres individuales (es decir, cada partido es un personaje único en lugar de todos los caracteres entre dos consecutivos "barra" s), posiblemente resultando en un potencial de alta sobrecarga si se trabaja con cadenas muy largas.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar] 
+6

En lugar de esas actualizaciones múltiples que nos obligan a leer las respuestas incorrectas antes de llegar a su respuesta final, ¿por qué no reescribir su respuesta para que sea completa, pero sin las partes malas algo confusas? Si alguien realmente se preocupa por el historial de edición, puede usar las funciones integradas de este sitio. –

+12

Han pasado dos años y medio desde que escribí esta respuesta, pero claro. – JAB

+2

malditamente duele, intente esto (? :(?! bar).) * – Bob

1

acaba de ocurrir algo más que se podía hacer. Es muy diferente de mi primera respuesta, ya que no usa expresiones regulares, así que decidí hacer una segunda respuesta.

Use el método de su elección split() equivalente en la cadena con la palabra a negar como argumento para qué dividir. Un ejemplo usando Python:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf' 
>>> text.split('bar') 
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf'] 

Lo bueno de hacerlo de esta manera, en Python al menos (No recuerdo si la funcionalidad sería la misma en, por ejemplo, Visual Basic o Java), que es que le permite saber indirectamente cuando se repitió "barra" en la cadena debido al hecho de que las cadenas vacías entre s "bar" se incluyen en la lista de los resultados (aunque la cadena vacía al principio se debe a la existencia de una "barra "al comienzo de la cadena). Si no quiere eso, simplemente puede eliminar las cadenas vacías de la lista.

+0

La pregunta específicamente pregunta acerca de regex ... –

+2

@Ajk_P sí, pero este tipo de respuestas pueden ayudar al OP a pensar fuera de la caja, podrían haberse obsesionado con las expresiones regulares sin darse cuenta de que podría ser resuelto sin ellos. – Petruza

21

me encontré con este hilo del foro al tratar de identificar una expresión regular para la siguiente declaración Inglés:

Dada una cadena de entrada, partido todo menos que esta cadena de entrada es exactamente 'bar'; por ejemplo, quiero hacer coincidir 'barrera' y 'barra', así como 'foo'.

Aquí es la expresión regular que se me ocurrió

^(bar.+|(?!bar).*)$ 
traducción

Mi Inglés de la expresión regular es "coincide con la cadena si ésta comienza con 'bar' y tiene al menos otro carácter, o si el cadena no comenzar con 'bar'

+0

@ReReqest: tendrá muchas más posibilidades de que le respondan esta pregunta si la publica como una pregunta separada. En eso puede proporcionar un enlace a esta pregunta si lo desea. Por el contenido de la pregunta, se ve bien pero no soy un gurú regex – Bostone

+1

Ese era el que estaba buscando. Realmente combina todo excepto el bar. –

1

tenía una lista de nombres de archivo, y quería excluir a algunos que, con este tipo de comportamiento (Rubí):.

files = [ 
    'mydir/states.rb',  # don't match these 
    'countries.rb', 
    'mydir/states_bkp.rb', # match these 
    'mydir/city_states.rb' 
] 
excluded = ['states', 'countries'] 

# set my_rgx here 

result = WankyAPI.filter(files, my_rgx) # I didn't write WankyAPI... 
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb'] 

aquí está mi solución:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|') 
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/ 

Mis supuestos para esta aplicación:

  • La cadena a ser excluido es al principio de la entrada, o inmediatamente después de una barra inclinada.
  • Las cadenas permitidas terminan en .rb.
  • Los nombres de archivo permitidos no tienen un carácter . antes del .rb.
3

La respuesta aceptada es buena, pero es realmente una solución para la falta de un operador de negación de sub-expresión simple en expresiones regulares. Esta es la razón por la cual grep --invert-match sale. Por lo tanto, en * nixes, puede lograr el resultado deseado utilizando tuberías y una segunda expresión regular.

grep 'something I want' | grep --invert-match 'but not these ones' 

Sigue siendo una solución, pero quizás más fácil de recordar.

17

Solución:

^(?!.*STRING1|.*STRING2|.*STRING3).*$ 

xxxxxx OK

xxxSTRING1xxx KO (es si se desea)

xxxSTRING2xxx KO (es si se desea)

xxxSTRING3xxx KO (es si se desea)

+1

gracias, esto me dio la información adicional que necesitaba para varias palabras – RozzA

1

espero para complementar la respuesta

A medida que el Chris especifica Regex Tutorial es un mejor recurso para el aprendizaje de expresiones regulares.

Sin embargo, realmente consumió tiempo para leer.

Hago una trampa para la conveniencia mnemotécnica.
[], (), {} llevando cada clase que es fácil de recordar.

Regex = 
{'single_character': ['[]', '.', {'negate':'^'}], 
'capturing_group' : ['()', '|', '\\', 'backreferences and named group'], 
'repetition'  : ['{}', '*', '+', '?', 'greedy v.s. lazy'], 
'anchor'   : ['^', '\b', '$'], 
'non_printable' : ['\n', '\t', '\r', '\f', '\v'], 
'shorthand'  : ['\d', '\w', '\s'], 
} 
Cuestiones relacionadas