首页 > 解决方案 > python 正则表达式中负后向限制的解决方法

问题描述

我正在编写一个正则表达式来识别文本中的问题,但前提是在我感兴趣的短语之前的 n=3 个单词内没有否定。这是我到目前为止所拥有的:

regex = r'''(?ix)     # case insensitive, verbose mode
\s+?
(?<!(not|no|never)){1,3}  # if this is within 3 words, you do not match, negative lookbehind
\s+?
(a|the|any|my|your)  # articles
\s+?
(issue|issues|problem|problems) # words of interest
'''

应该匹配:

matches = [
"a problem",
"the issue",
"any of the issues",
"not even close to being your issue",
]

不应该匹配:

non_matches = [
  "not a problem",
  "never your problem",
  "not the issue",
  "not overwhelmingly your issue",
  "not too close your issue"
]

如果我在没有负面后视的情况下运行:

regex2 = r'''(?ix)  # case insensitive, verbose
(a|the|any|my|your)    # articles
\s+?
(issue|issues|problem|problems) # words of interest
'''

我得到正确的正面匹配。

>>> for p in matches:
...   print(re.findall(regex2, p))
[('a', 'problem')]
[('the', 'issue')]
[('the', 'issue')]
[('your', 'issue')]

但是,如果我包括为了正确排除否定匹配而需要的否定前瞻,我会得到:

re.error: look-behind requires fixed-width pattern

我知道这只是 python 正则表达式引擎的一个限制,但是在这种情况下常用的适当解决方法是什么?有没有一种简单的方法可以将 0、1、2、3 模式组合在一起来处理它?还有什么?

标签: pythonregex

解决方案


您可以安装 PyPi 正则表达式模块并忘记后向模式限制。

import regex
rx = r'''(?ix)     # case insensitive, verbose mode
(?<!\b(?:not|no|never)(?:\s+\S+){0,2}\s+)  # if this is within 3 words, you do not match, negative lookbehind
(a|the|any|my|your)  # articles
\s+
(issue|issues|problem|problems)\b # words of interest
'''

接着

for p in matches:
    print(regex.findall(rx, p))

# [('a', 'problem')]
# [('the', 'issue')]
# [('the', 'issues')]
# [('your', 'issue')]

for p in non_matches:
    print(regex.findall(rx, p))

# []
# []
# []
# []
# []

请参阅Python 演示

笔记:

  • (?<!\b(?:not|no|never)(?:\s+\S+){0,2}\s+)是一个否定的向后查找,如果当前位置前面紧跟一个完整的 word notno或者never然后有零个、一个或两个重复的一个或多个空格,后跟一个或多个非空格,然后是一个或多个空格,则匹配失败。因此,总而言之,负面词最多可以出现 3 个远离感兴趣词的词。
  • (?:...)在不需要提取的模式部分周围使用非捕获组,如果捕获组在模式中定义,则始终只返回捕获re.findallregex.findall否则,您将需要一种.finditer方法。
  • 注意(issue|issues|problem|problems)\b:末尾的单词边界让正则表达式引擎将这些单词作为整个单词进行匹配,如果存在issues,它将完整返回该单词。如果您不使用\b并且仍然希望获得[('the', 'issues')]第三个matches字符串的结果,则需要将issues替代项放在第一个替代项之前,issue因为第一个替代项匹配“获胜”,其余的不尝试。

推荐阅读