Perl Regex Отрицательный взгляд за неправильным соответствием (SAS) - PullRequest
1 голос
/ 05 марта 2019

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

Вот выражение, которое оценивается:

hlhx=PRXPARSE('/yes|(?<!no).*homeless.*(for|in|year|age)|at\sage|couch|was\shomeless|multiple|
                        lived.*streets|(?<!\bnot).*at\srisk|has\sbeen|high\srisk|currently\shomeless|
                        liv(es|ing|ed).*car|many|(?<!\bno).*(hx|history|h.?o)|(?<!\bno)(?<!low).+risk/ox');

Пара ответов не должна соответствовать этому выражению, но должна:

  • no hx of homelessness and low risk of homelessness
  • owns home, no h/o homelessness; low risk for homelessness
  • no and little risk

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

РЕДАКТИРОВАТЬ: Чтобы уточнить, какая часть выражения вызывает совпадение с записями, подобными тем, которые есть в списке?

Лучший, Лорен

1 Ответ

1 голос
/ 05 марта 2019

Вот как ваше регулярное выражение соответствует 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
     ^^^^^^^

и сразу отклоняет всю строку.

...