2012-03-23 19 views
7

que estoy tratando de construir una expresión regular algo como esto:expresiones regulares: negativa de preanálisis entre dos partidos

[match-word] ... [exclude-specific-word] ... [match-word] 

Esto parece funcionar con una visión hacia adelante negativo, pero estoy corriendo en un problema cuando tengo un caso como este:

[match-word] ... [exclude-specific-word] ... [match-word] ... [excluded word appears again] 

quiero la frase anterior a la altura, pero el aspecto de la ventaja negativa entre la primera y la segunda palabra que concordaba "se derrama sobre" lo que la segunda palabra nunca es igualada.

Veamos un ejemplo práctico.

Quiero hacer coincidir cada oración que tiene la palabra "i" y la palabra "pastel", pero no la palabra "odio" entre esas dos palabras. tengo estas tres frases:

i sure like eating pie, but i love donuts <- Want to match this 
i sure like eating pie, but i hate donuts <- Want to match this 
i sure hate eating pie, but i like donuts <- Don't want to match this 

tengo esta expresión regular:

^i(?!.*hate).*pie   - have removed the word boundaries for clarity, original is: ^i\b(?!.*\bhate\b).*\bpie\b 

que coincide con la primera frase, pero no la segunda, porque el aspecto negativo de la ventaja escanea toda la cadena.

¿Hay alguna manera de limitar el aspecto negativo anticipado, de modo que quede satisfecho si encuentra "pie" antes de encontrar "odio"?

Nota: en mi aplicación, puede haber otros términos que siguen a esta expresión regular (que está construido de forma dinámica a partir de un motor de búsqueda de la gramática), por ejemplo:

^i(?!.*hate).*pie.*donuts 

actualmente estoy usando JRegex, pero probablemente podría cambiar a JDK expresión regular si es necesario

actualización: me olvidó mencionar algo en mi pregunta inicial:

es posible que el "constructo negativo" existe más en la sente nce, y quiero hacer coincidir la oración si es posible, incluso si el constructo "negativo" existe más arriba.

para aclarar, un vistazo a estas frases:

i sure like eating pie, but i love donuts <- Want to match this 
i sure like eating pie, but i hate donuts <- Want to match this 
i sure hate eating pie, but i like donuts <- Don't want to match this 
i sure like eating pie, but i like donuts and i hate making pie <- Do want to match this 

respuesta de Rob funciona perfectamente para esta restricción adicional, por lo que estoy aceptando que uno.

Respuesta

2

En todos los personajes entre su inicio y parada palabras, usted tiene que asegurarse de que no coincide con su negativa o detener la palabra. Del modo siguiente (He incluido un poco de espacio en blanco para facilitar la lectura):

^i ((?!hate|pie) .)* pie 

Aquí es un programa Python para probar cosas.

import re 

test = [ ('i sure like eating pie, but i love donuts', True), 
     ('i sure like eating pie, but i hate donuts', True), 
     ('i sure hate eating pie, but i like donuts', False) ] 

rx = re.compile(r"^i ((?!hate|pie).)* pie", re.X) 

for t,v in test: 
    m = rx.match(t) 
    print t, "pass" if bool(m) == v else "fail" 
+4

espacio en blanco en la expresión regular no ayuda a la legibilidad, su único confuso – Aprillion

+1

@death El espacio en blanco es válido en una expresión regular pitón, con la bandera "prolija". Confundir para usted, útil para mí ... tenemos diferentes opiniones. (También es fácil de editar). – rob

+0

¿por qué no usaste el espacio en blanco en tu ejemplo de python? – Aprillion

2

para que coincida con ninguna C entre ...A...B...

prueba en python:

$ python 
>>> import re 
>>> re.match(r'.*A(?!.*C.*B).*B', 'C A x B C') 
<_sre.SRE_Match object at 0x94ab7c8> 

Así consigo este regex:

.*\bi\b(?!.*hate.*pie).*pie 
2

Esta expresión regular debe trabajar para usted

^(?!i.*hate.*pie)i.*pie.*donuts 

Explicación

"^" +   // Assert position at the beginning of a line (at beginning of the string or after a line break character) 
"(?!" +  // Assert that it is impossible to match the regex below starting at this position (negative lookahead) 
    "i" +   // Match the character “i” literally 
    "." +   // Match any single character that is not a line break character 
     "*" +   // Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
    "hate" +  // Match the characters “hate” literally 
    "." +   // Match any single character that is not a line break character 
     "*" +   // Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
    "pie" +  // Match the characters “pie” literally 
")" + 
"i" +   // Match the character “i” literally 
"." +   // Match any single character that is not a line break character 
    "*" +   // Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
"pie" +  // Match the characters “pie” literally 
"." +   // Match any single character that is not a line break character 
    "*" +   // Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
"donuts"  // Match the characters “donuts” literally 
Cuestiones relacionadas