Regex: негативный прогноз между двумя матчами - PullRequest
7 голосов
/ 23 марта 2012

Я пытаюсь построить регулярное выражение примерно так:

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

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

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

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

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

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

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

Обновление : Я забыл упомянуть кое-что в своем первоначальном вопросе:

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

Чтобы уточнить, посмотрите на эти предложения:

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

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

Ответы [ 4 ]

3 голосов
/ 24 марта 2012

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

^(?!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
2 голосов
/ 24 марта 2012

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

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

Вот программа на python для тестирования.

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"
2 голосов
/ 23 марта 2012

Для совпадения нет 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
0 голосов
/ 05 июля 2018

используя код сверху ответа

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"

Я получаю

i sure like eating pie, but i love donuts pass
i sure like eating pie, but i hate donuts pass
i sure hate eating pie, but i like donuts pass
...