2012-03-23 15 views
7

Próbuję zbudować regex trochę tak:Regex: ujemne wygląd wyprzedzeniem dwóch meczów

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

To wydaje się działać z ujemnym antycypowana, ale biegnę do problemu kiedy mam sprawę tak:

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

chcę powyższe zdanie, aby dopasować, ale negatywny look-ahead pomiędzy pierwszym i drugim dopasowane słowa „wylewa”, więc drugie słowo nie pasuje.

Spójrzmy na praktyczny przykład.

Nie pasuję do każdego zdania, które ma słowo "i" i słowo "ciasto", ale nie słowo "nienawiść" pomiędzy tymi dwoma słowami. mam te trzy zdania:

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 

mam tego regex:

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

który pasuje pierwsze zdanie, ale nie drugi, ponieważ ujemne wygląd wyprzedzeniem skanuje cały ciąg.

Czy istnieje sposób na ograniczenie negatywnego patrzenia w przyszłość, aby był usatysfakcjonowany, jeśli napotka "ciasto", zanim napotka "nienawiść"?

Uwaga: w mojej realizacji, mogą obowiązywać inne warunki naśladujących tego regex (jest zbudowany dynamicznie z wyszukiwarki gramatyka), na przykład:

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

obecnie używam JRegex, ale prawdopodobnie może przełączyć do JDK Regex razie potrzeby

Aktualizacja: Zapomniałem wspomnieć coś w moim początkowym pytaniu:

Jest możliwe, że „negatywne konstrukt” istnieje dalej w Sente nce, i chcę dopasować zdanie, jeśli jest to możliwe, nawet jeśli "negatywna" konstrukcja istnieje dalej.

Aby wyjaśnić, spójrz na tych zdaniach:

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 

odpowiedź Roba działa doskonale na tym dodatkowym ograniczeniem, więc jestem przyjmując, że jeden.

Odpowiedz

2

Na każdym znaku pomiędzy twoją start i stop słowy, trzeba upewnić się, że nie pasuje do ujemny lub zatrzymać słowo. W ten sposób (tam, gdzie dodano małą białą przestrzeń dla czytelności):

Oto program python do testowania rzeczy.

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

białe miejsca w regex nie pomaga czytelność, jego tylko mylące – Aprillion

+1

@death Biała spacja jest ważna w regex Pythona, z „gadatliwym” flagi. Mylące dla ciebie, pomocne dla mnie ... mamy różne opinie. (Łatwo to również wyedytować.) – rob

+0

dlaczego więc nie użyłeś białego spacji w twoim pythonie? – Aprillion

2

Aby dopasować nie C między ...A...B...

testowy w python:

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

Więc mam ten regex:

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

Ten regex powinien pracować dla Ciebie

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

Wyjaśnienie

"^" +   // 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