Вот как ваше регулярное выражение соответствует no and little risk
:
Одна из ветвей в вашем регулярном выражении: ...|(?<!\bno)(?<!low).+risk
.
Движок регулярных выражений запускается попыткой совпадения в каждой позиции целевой строки, начиная с начала:
no and little risk
^
Первое ограничение заключается в том, что текущей позиции не может предшествовать граница слова, за которой следует «нет» (из-за (?<!\bno)
). Это условие выполняется: началу целевой строки ничего не предшествует.
Вторым ограничением является то, что текущей позиции не может предшествовать "низкий уровень" (из-за (?<!low)
). Это условие также выполняется (см. Выше).
Затем мы сопоставляем один или несколько не-новых символов, но как можно больше из них (это часть .+
). Здесь мы изначально потребляем всю строку:
no and little risk
------------------^
Но тогда регулярное выражение требует совпадения risk
, что не удается (в целевой строке больше не осталось символов). Это заставляет .+
возвращаться назад и потреблять все меньше и меньше символов, пока это не произойдет:
no and little risk
--------------^
На этом этапе risk
успешно совпадает и регулярное выражение заканчивается.
Основная проблема в том, что вы хотите сделать это (?<!\bno.+)(?<!low.+)risk
, но вы написали (?<!\bno)(?<!low).+risk
. Это две совершенно разные вещи!
Первый означает «соответствовать» риску, но только если ему не предшествует ни «нет», ни «низкий» где-либо в строке (до 1 символа перед «риском») ». Последнее означает «соответствовать любой непустой подстроке, за которой следует« риск », если ей не предшествует ни« нет », ни« низкий »». Это дает механизму регулярных выражений свободу поиска любой подходящей позиции в строке, если ей не предшествует сразу "нет" или "низкий уровень", а где-то следует ". + Риск".
К сожалению, (?<!\bno.+)
не является допустимым регулярным выражением, поскольку проверочные утверждения должны иметь фиксированную длину.
Один из возможных обходных путей - сделать следующее:
^(?!.*(?:\bno|low).+risk).*risk
Это говорит: Начиная с начала строки, сначала убедитесь, что нет «нет» или «низкий», а затем «риск» в любом месте, а затем сопоставьте «риск» в любом месте строки.
Это не совсем эквивалентно (гипотетической) версии с изменяемой шириной, потому что она соответствовала бы
risk no risk
^^^^
из-за наличия «риска» без «no», предшествующего ему, тогда как этот обходной путь сначала находит
risk no risk
^^^^^^^
и сразу отклоняет всю строку.