У меня возникли проблемы с пониманием более тонких деталей негативных регулярных выражений. После чтения Regex lookahead, lookbehind и атомных групп, я подумал, что у меня было хорошее резюме отрицательных обращений, когда я нашел это описание:
(?!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 = "уродливый" ): "И она пахнет влажной собакой".
- Тест 2 ($ arg = "смотрит" ): "Йомама уродливая" .
- Тест 3 ($ arg = "запахи" ): "Йомама уродливая" .
Фактические результаты:
- Тест 1 ($ arg = "уродливый" ): "И она пахнет влажной собакой". (Success)
- Тест 2 ($ arg = "смотрит" ): "Йомама уродливая" . (Success)
- Тест 3 ($ arg = "запахи" ): сбой, отсутствие соответствия
Сначала я думал, что тест 3 потерпел неудачу, потому что ([A-Z].*?\.)
был слишком жадным и сопоставлял оба предложения; однако (?:(?![A-Z].*?$arg.*?\.))([A-Z][^\.]*?\.)
тоже не работает. Затем я задавался вопросом, была ли проблема с реализацией python-отрицательного представления, но perl дал мне точно такой же результат.
Наконец, я нашел решение, мне пришлось отклонять периоды в моей части .*?
выражений, используя [^\.]*?
; поэтому это регулярное выражение работает: (?:(?![A-Z][^\.]*?$arg[^\.]*?\.))([A-Z][^\.]*?\.)
Вопрос
Однако у меня есть еще одна проблема; "Йомама уродлив". не имеет в себе "запахов". Итак, если .*?
предполагается не-жадным совпадением, почему я не могу завершить тест 3 с помощью (?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)
?
ИЗМЕНИТЬ
В свете @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.'