Отрицательная жадность регулярных выражений с упреждением (почему. *? Слишком жадные)

У меня проблемы с пониманием более тонких деталей регулярных выражений негативного просмотра вперед. Прочитав Regex lookahead, lookbehind и атомарные группы , я подумал, что у меня есть хорошее резюме отрицательных lookahead, когда я нашел это описание:

(?! REGEX_1) REGEX_2

Соответствует, только если REGEX_1 не соответствует; после проверки REGEX_1 поиск REGEX_2 начинается с той же позиции.

Надеясь, что я понял алгоритм, я приготовил тестовое оскорбление из двух предложений; Я хотел найти предложение без определенного слова. В частности ...

Оскорбление: 'Йомама уродлив. И она пахнет мокрой собакой. »

Требования :

  • Тест 1: Вернуть предложение без« уродливого ».
  • Тест 2: Вернуть предложение без« взглядов ».
  • Тест 3: Вернуть предложение без «запахов».

Я назначил тестовые слова для $ arg и использовал (?: (?! [AZ]. *? $ Arg. * ? \.)) ([AZ]. *? \.) для реализации теста.

  • (?! [AZ]. *? $ Arg. *? \.) - отрицательный прогноз отклонить предложение с тестовым словом
  • ([AZ]. *? \.) соответствует по крайней мере одно предложение.

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

Ожидаемые результаты :

  • Тест 1 ($ arg = "ugly"): «И она пахнет мокрой собакой.»
  • Тест 2 ($ arg = "выглядит"): «Йомама уродлив».
  • ($ arg = "пахнет"): "Йомама уродливая."

Фактические результаты :

  • Тест 1 ($ arg = "уродливо"): "И она пахнет мокрой собакой". (Успех)
  • Тест 2 ($ arg = "выглядит"): "Йомама уродлив". (Успех)
  • Тест 3 ($ arg = "пахнет"): Неудачный, нет совпадений

Сначала я думал, что Тест 3 не прошел, потому что ([AZ]. *? \.) был слишком жадным и соответствовал обоим предложениям; однако (?: (?! [AZ]. *? $ arg. *? \.)) ([AZ] [^ \.] *? \.) тоже не работал. Затем я поинтересовался, есть ли проблема с реализацией отрицательного просмотра вперед в Python, но Perl дал мне точно такой же результат.

Наконец я нашел решение, мне пришлось отклонить точки в моей части . *? выражений, используя [^ \.] *? ; поэтому это регулярное выражение работает: (?: (?! [AZ] [^ \.] *? $ arg [^ \.] *? \.)) ([AZ] [^ \.] *? \. )

Вопрос

Однако у меня есть другое беспокойство; «Йомама уродлив». не имеет "запахов". Итак, если . *? должно быть нежадным совпадением, почему я не могу завершить тест 3 с помощью (?: (?! [AZ]. *? $ Arg. * ? \.)) ([AZ]. *? \.) ?

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.'

19
задан Community 23 May 2017 в 11:59
поделиться