Perl Regex 负后视不正确匹配 (SAS)
Perl Regex Negative Lookbehind Incorrect Match (SAS)
在 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
显然我没有正确指定我的回顾。任何帮助将不胜感激。
编辑:更准确地说,表达式的哪一部分与列表中的条目匹配?
最好的,
劳伦
下面是您的正则表达式如何匹配 no and little risk
:
正则表达式中的一个分支是 ...|(?<!\bno)(?<!low).+risk
。
正则表达式引擎首先尝试在目标字符串中的每个位置进行匹配,从开头开始:
no and little risk
^
第一个限制条件是当前位置不能在单词边界前面加上"no"(由于(?<!\bno)
)。满足此条件:目标字符串的开头没有任何内容。
第二个限制条件是当前位置前面不能有"low"(由于(?<!low)
)。这个条件也满足(见上文)。
然后我们匹配一个或多个非换行符,但尽可能多(这是 .+
部分)。在这里,我们最初使用整个字符串:
no and little risk
------------------^
但是正则表达式需要匹配 risk
,这会失败(目标字符串中没有更多字符)。这导致 .+
回溯并消耗越来越少的字符,直到发生这种情况:
no and little risk
--------------^
至此,risk
匹配成功,正则表达式结束。
基本问题是你想做的是(?<!\bno.+)(?<!low.+)risk
,但你写的却是(?<!\bno)(?<!low).+risk
。这是两个截然不同的东西!
前者表示"match 'risk', but only if it's not preceded by 'no' or 'low' anywhere in the string (up to 1 character before 'risk')"。后者表示"match any non-empty substring followed by 'risk', as long as it's not preceded by either 'no' or 'low'"。这使正则表达式引擎可以自由地在字符串中查找任何匹配的位置,只要它不是紧跟在 "no" 或 "low" 之前并且在某处紧跟“.+risk”即可。
很遗憾,(?<!\bno.+)
不是有效的正则表达式,因为回顾断言必须具有固定长度。
一种可能的解决方法是执行以下操作:
^(?!.*(?:\bno|low).+risk).*risk
这是说:从字符串的开头开始,首先确保没有"no"或"low"后跟[=67=]的任何地方,然后匹配"risk"任何地方在字符串中。
这与(假设的)可变宽度后视版本不太等同,因为后者会匹配
risk no risk
^^^^
由于 "risk" 前面没有 "no",而此解决方法首先找到
risk no risk
^^^^^^^
并立即拒绝整个字符串。
在 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
显然我没有正确指定我的回顾。任何帮助将不胜感激。
编辑:更准确地说,表达式的哪一部分与列表中的条目匹配?
最好的, 劳伦
下面是您的正则表达式如何匹配 no and little risk
:
正则表达式中的一个分支是 ...|(?<!\bno)(?<!low).+risk
。
正则表达式引擎首先尝试在目标字符串中的每个位置进行匹配,从开头开始:
no and little risk
^
第一个限制条件是当前位置不能在单词边界前面加上"no"(由于(?<!\bno)
)。满足此条件:目标字符串的开头没有任何内容。
第二个限制条件是当前位置前面不能有"low"(由于(?<!low)
)。这个条件也满足(见上文)。
然后我们匹配一个或多个非换行符,但尽可能多(这是 .+
部分)。在这里,我们最初使用整个字符串:
no and little risk
------------------^
但是正则表达式需要匹配 risk
,这会失败(目标字符串中没有更多字符)。这导致 .+
回溯并消耗越来越少的字符,直到发生这种情况:
no and little risk
--------------^
至此,risk
匹配成功,正则表达式结束。
基本问题是你想做的是(?<!\bno.+)(?<!low.+)risk
,但你写的却是(?<!\bno)(?<!low).+risk
。这是两个截然不同的东西!
前者表示"match 'risk', but only if it's not preceded by 'no' or 'low' anywhere in the string (up to 1 character before 'risk')"。后者表示"match any non-empty substring followed by 'risk', as long as it's not preceded by either 'no' or 'low'"。这使正则表达式引擎可以自由地在字符串中查找任何匹配的位置,只要它不是紧跟在 "no" 或 "low" 之前并且在某处紧跟“.+risk”即可。
很遗憾,(?<!\bno.+)
不是有效的正则表达式,因为回顾断言必须具有固定长度。
一种可能的解决方法是执行以下操作:
^(?!.*(?:\bno|low).+risk).*risk
这是说:从字符串的开头开始,首先确保没有"no"或"low"后跟[=67=]的任何地方,然后匹配"risk"任何地方在字符串中。
这与(假设的)可变宽度后视版本不太等同,因为后者会匹配
risk no risk
^^^^
由于 "risk" 前面没有 "no",而此解决方法首先找到
risk no risk
^^^^^^^
并立即拒绝整个字符串。