如何让Python的负面外观不那么贪婪?

Chr*_*pin 8 python regex

我已经阅读了所有相关帖子并搜索了互联网,但这真的打败了我.

我有一些包含日期的文字.
我想捕获日期,但如果它之前有一个特定的短语,则不会.

一个简单的解决方案是为我的RegEx添加负面的lookbehind.

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

19-2-11 15-4-11
这样的事情
,例如29-5-11

这是我的正则表达式:

(?<!as of )(\d{1,2}-\d{1,2}-\d{2})
Run Code Online (Sandbox Code Playgroud)

预期成绩:

['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})
Run Code Online (Sandbox Code Playgroud)

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

显然我的负面看法是贪婪 - 比我的日期捕获更多,所以它从它那里偷了一个数字并且失败了.我已经尝试过各种方法来纠正我能想到的贪婪,但我只是不知道要解决这个问题.

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

如何让Python的负面外观不那么贪婪?

Mar*_*ers 7

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

要修复它,您可能需要在匹配之前使用单词边界:

(?<!as of )\b(\d{1,2}-\d{1,2}-\d{2})
#          ^^ add this
Run Code Online (Sandbox Code Playgroud)

  • 怎么样:`(?<!as)(?<!\ s)\ s*\b(\ d {1,2} - \d {1,2} - \d {2})` (2认同)

ovg*_*vin 1

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

它通过短语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})
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)