Perl正则表达式负向后查找不正确匹配(SAS)

时间:2019-03-05 16:09:55

标签: regex sas regex-lookarounds negative-lookbehind

在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 个答案:

答案 0 :(得分:1)

这是您的正则表达式与no and little risk匹配的方式:

正则表达式中的一个分支是...|(?<!\bno)(?<!low).+risk

regex引擎首先在目标字符串中的每个位置尝试匹配,从头开始:

no and little risk
^

第一个约束是,当前位置不能在单词边界之后加上“ no”(由于(?<!\bno))。满足此条件:目标字符串的开头没有任何前缀。

第二个约束是当前位置不能以“ low”开头(由于(?<!low))。此条件也得到满足(请参见上文)。

然后,我们匹配一个或多个非换行符,但是要尽可能多地匹配它们(这是.+部分)。在这里,我们首先使用整个字符串:

no and little risk
------------------^

但是正则表达式要求匹配risk,该匹配失败(目标字符串中没有剩余的字符)。这会导致.+回溯并消耗越来越少的字符,直到发生这种情况:

no and little risk
--------------^

此时,risk成功匹配,并且正则表达式完成。

基本问题是您想做的是(?<!\bno.+)(?<!low.+)risk,但是您写的是(?<!\bno)(?<!low).+risk。这是两个截然不同的东西!

前者的意思是“匹配'risk',但前提是在字符串的任何位置(在'risk'之前最多1个字符)之前都没有'no'或'low'。后者的意思是“匹配任何非空的子字符串,后跟“风险”,只要它前面没有“否”或“低”。这使正则表达式引擎可以自由地在字符串中查找任何匹配的位置,只要它不立即以“ no”或“ low”开头,并且在某处后面是“。+ risk”即可。

不幸的是,(?<!\bno.+)不是有效的正则表达式,因为后置断言必须具有固定的长度。

一种可能的解决方法是执行以下操作:

^(?!.*(?:\bno|low).+risk).*risk

这是说:从字符串的开头开始,首先确保没有“ no”或“ low”,然后在任何地方都没有“ risk”,然后在字符串中的任何地方匹配“ risk”。

这与(假设的)可变宽度后向版本并不完全等效,因为该版本已经匹配

risk no risk
^^^^

由于存在“风险”而没有“否”,因此首先找到了此解决方法

risk no risk
     ^^^^^^^

并立即拒绝整个字符串。