У меня проблемы с пониманием мелких деталей регулярных выражений с отрицательным прогнозом. Прочитав Regex lookahead, lookbehind и atomic groups , я подумал, что у меня было хорошее резюме негативных взглядов, когда я нашел это описание:
(?!REGEX_1)REGEX_2
Совпадение, только если REGEX_1
не совпадает; после проверки REGEX_1
поиск REGEX_2
начинается с той же позиции.
Надеясь, что я понял алгоритм, я приготовил тестовое оскорбление из двух предложений; Я хотел найти предложение без определенного слова. В частности ...
Оскорбление: 'Йомама безобразна. И она пахнет как мокрая собака. '
Требования
- Тест 1: вернуть предложение без «уродливого».
- Тест 2: вернуть предложение без «взглядов».
- Тест 3: вернуть предложение без «запахов».
Я назначил тестовые слова для $arg
и использовал (?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)
для реализации теста.
(?![A-Z].*?$arg.*?\.)
- отрицательный взгляд на отклонение предложения с тестовым словом
([A-Z].*?\.)
соответствует как минимум одно предложение.
Важным моментом, по-видимому, является понимание того, где механизм регулярных выражений начинает сопоставляться после обработки отрицательного результата.
Ожидаемые результаты :
- Тест 1 ($ arg = "ugly"): "И она пахнет как мокрая собака".
- Тест 2 ($ arg = "look"): "Йомама безобразна".
- Тест 3 ($ arg = "запах"): "Йомама безобразна".
Фактические результаты :
- Тест 1 ($ arg = "ugly"): "И она пахнет как мокрая собака". (Success)
- Тест 2 ($ arg = "look"): "Йомама безобразна". (Success)
- Тест 3 ($ arg = "smells"): Не удалось, не найдено совпадений
Сначала я думал, что Тест 3 провалился, потому что ([A-Z].*?\.)
был слишком жадным и соответствовал обоим предложениям; однако (?:(?![A-Z].*?$arg.*?\.))([A-Z][^\.]*?\.)
тоже не сработало. Затем я задался вопросом, была ли проблема с реализацией python негативного просмотра, но perl дал мне точно такой же результат.
Наконец, я нашел решение, мне пришлось отклонить точки в моей .*?
части выражений, используя [^\.]*?
; так что это регулярное выражение работает: (?:(?![A-Z][^\.]*?$arg[^\.]*?\.))([A-Z][^\.]*?\.)
Вопрос
Однако у меня есть другая проблема; "Йомама безобразна". не имеет "запахов" в нем. Итак, если .*?
считается не жадным совпадением, почему я не могу завершить Тест 3 с (?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)
?
EDIT
В свете превосходного предложения @ bvr использовать -Mre=debug
, я рассмотрю это еще немного после работы. Похоже, что описание Сета на данный момент точное. До сих пор я узнал, что отрицательные прогнозные выражения будут совпадать всякий раз, когда это возможно, даже если я добавлю не жадные операторы .*?
в NLA.
Реализация Python
import re
def test_re(arg, INSULTSTR):
mm = re.search(r'''
(?: # No grouping
(?![A-Z].*?%s.*?\.)) # Negative zero-width
# assertion: arg, followed by a period
([A-Z].*?\.) # Match a capital letter followed by a period
''' % arg, INSULTSTR, re.VERBOSE)
if mm is not None:
print "neg-lookahead(%s) MATCHED: '%s'" % (arg, mm.group(1))
else:
print "Unable to match: neg-lookahead(%s) in '%s'" % (arg, INSULTSTR)
INSULT = 'Yomama is ugly. And, she smells like a wet dog.'
test_re('ugly', INSULT)
test_re('looks', INSULT)
test_re('smells', INSULT)
Реализация Perl
#!/usr/bin/perl
sub test_re {
$arg = $_[0];
$INSULTSTR = $_[1];
$INSULTSTR =~ /(?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)/;
if ($1) {
print "neg-lookahead($arg) MATCHED: '$1'\n";
} else {
print "Unable to match: neg-lookahead($arg) in '$INSULTSTR'\n";
}
}
$INSULT = 'Yomama is ugly. And, she smells like a wet dog.';
test_re('ugly', $INSULT);
test_re('looks', $INSULT);
test_re('smells', $INSULT);
выход
neg-lookahead(ugly) MATCHED: 'And, she smells like a wet dog.'
neg-lookahead(looks) MATCHED: 'Yomama is ugly.'
Unable to match: neg-lookahead(smells) in 'Yomama is ugly. And, she smells like a wet dog.'