9

我已经阅读了所有相关的帖子并搜索了互联网,但这真的让我感到震惊。

我有一些包含日期的文本。
我想捕获日期,但如果它前面有某个短语,则不是。

一个直截了当的解决方案是在我的 RegEx 中添加一个否定的lookbehind。

以下是一些示例(使用 findall)。
如果日期前面没有短语“as of”,我只想捕获日期。

19-2-11
某事 15-4-11
诸如此类 29-5-11

这是我的正则表达式:

(?<!as of )(\d{1,2}-\d{1,2}-\d{2})

预期成绩:

['19-2-11']
['15-4-11']
[]

实际结果:

['19-2-11']
['15-4-11']
['9-5-11']

请注意,这是 9 而不是 29。如果我更改\d{1,2}为类似于\d{2}第一个模式的实体:

bad regex for testing: (?<!as of )(\d{2}-\d{1,2}-\d{2})

然后我得到了我的预期结果。当然这不好,因为我想匹配 2 位数的天数和个位数的天数。

显然,我的消极后视非常贪婪 - 比我的日期捕获更重要,所以它从中窃取了一个数字并失败了。我已经尝试了所有纠正我能想到的贪婪的方法,但我只是不知道如何解决这个问题。

我希望我的日期捕获与最大的贪婪相匹配,然后应用我的负面回顾。这可能吗?我的问题似乎很好地利用了负面的后视,而不是过于复杂。如果必须的话,我确信我可以用另一种方式完成它,但我想学习如何做到这一点。

如何使 Python 的消极后视不那么贪婪?

4

3 回答 3

8

这与贪婪无关。贪婪不会改变正则表达式是否匹配——它只会改变执行搜索的顺序。这里的问题是您的正则表达式需要更具体以避免不必要的匹配。

要修复它,您可以在匹配之前需要一个单词边界:

(?<!as of )\b(\d{1,2}-\d{1,2}-\d{2})
#          ^^ add this
于 2012-05-02T20:27:37.030 回答
1

原因不是因为向后看是贪婪的。发生这种情况是因为正则表达式引擎尝试在每个位置匹配模式。

它首先通过短语such and such as of 29-5-11成功匹配(?<!as of ),但未能匹配\d{1,2}

但随后引擎会在该位置找到自身such and such as of !29-5-11(标有!)。但在这里它无法匹配(?<!as of )

它前进到下一个位置:such and such as of 2!9-5-11。在哪里成功匹配(?<!as of )然后\d{1,2}.

如何避免?

一般的解决方案是尽可能清晰地制定模式。

在这种情况下,我会在数字前面加上必要的空格或字符串的开头。

(?<!as of)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2})

Mark Byers 的解决方案也很不错。

我认为了解正则表达式引擎以这种方式运行并给出不需要的结果的原因非常重要。

顺便说一句,如果有 2 个或更多空格,我上面给出的解决方案将不起作用。它不起作用,因为这里的拳头位置与such and such as of ! 29-5-11上述模式匹配。

可以做些什么来避免它?

不幸的是,Python 正则表达式引擎中的lookbehind 不支持量词+*.

我认为最简单的解决方案是确保之前没有空格(?:^|\s+)(这意味着所有空格都被(?:^|\s+)任何非空格文本直接占用(如果文本是as of,则终止前进并回溯到下一个起始位置开始搜索所有在搜索文本的下一个位置重新开始)。

re.search(r'(?<!as of)(?<!\s)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2})','such and such as of  29-5-11').group(1)
于 2012-05-02T20:49:12.770 回答
-1

一个简单的解决方案是在使用正则表达式隔离日期之前丢弃所有匹配“as of”的行。

于 2012-05-02T21:15:37.927 回答