2012-03-23 2 views
7

Я пытаюсь построить регулярное выражение несколько, как это:Regex: отрицательный взгляд вперед между двумя матчами

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

Это похоже на работу с отрицательным заглядывая вперёд, но я бегу в проблему когда у меня есть такой случай:

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

Я хочу выше предложение, чтобы соответствовать, но отрицательным смотреть вперед между первым и вторым соответствующим словом «перетекает», так что второе слово никогда не совпадают.

Давайте рассмотрим практический пример.

Я не согласен со всеми предложениями, в которых есть слово «i» и слово «пирог», но не слово «ненависть» между этими двумя словами. У меня есть эти три предложения:

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(?!.*hate).*pie   - have removed the word boundaries for clarity, original is: ^i\b(?!.*\bhate\b).*\bpie\b 

который соответствует первое предложение, но не второй, так как отрицательный взгляд вперед сканирует всю строку.

Есть ли способ ограничить негативный внешний вид, чтобы он был удовлетворен, если он встречает «пирог», прежде чем он встретит «ненависть»?

Примечание: в моей реализации, могут существовать и другие термины, следующих за этим регулярное выражение (оно динамически собираемого из поисковой грамматике двигателя), например:

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

настоящее время я использую JRegex, но, вероятно, может переключиться в JDK Regex при необходимости

Update: Я забыл упомянуть, что-то в моем первоначальный вопрос:

Вполне возможно, что «негативный конструкт» существует далее в сэнтэ nce, и я хочу соответствовать предложению, если это возможно, даже если «отрицательная» конструкция существует дальше.

Для уточнения, посмотрите на эти предложения:

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 

ответ Роба работает отлично для этого дополнительного ограничения, поэтому я принять этот один.

ответ

2

В каждом персонаже между вашим началом и остановить словами, вы должны убедиться, что он не соответствует вашей отрицательной или остановить слово. Как это (там, где я включил немного белого пространства для удобства чтения):

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

Вот питон программа для проверки вещей.

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

белого пространство в регулярном выражении не помогает читаемости, его только запутанный – Aprillion

+1

@death Пробелы действует в питоне регулярного выражении, с «многословным» флагом. Сбив с толку, полезный для меня ... у нас разные мнения. (Это также легко отредактировать.) – rob

+0

, так почему же вы не использовали пробел в своем примере на python? – Aprillion

2

Чтобы соответствовать не C между ...A...B...

испытания в python:

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

Так я получаю это регулярное выражение:

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

Это регулярное выражение должно работать для вас

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

Объяснение

"^" +   // 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 
Смежные вопросы