正则表达式负向后视没有按预期工作

Regex negative look behind isn't working as expected

在 python 中我使用了这个正则表达式

(?<!\d\d\d)(\s?lt\.?\s?blue)

在此字符串上

ltblue
500lt.blue
4009 lt blue
lt. blue
032 lt red

我希望它能捕捉到这个

ltblue
lt. blue

但它却捕获了

ltblue
lt. blue
lt blue

根据我的写法,我认为它不应该在 4009 之后捕获 'lt blue',但出于某种原因,\s?在 'lt' 似乎不起作用之前,有人知道我如何更改正则表达式以获得预期的输出吗?

如果数字总是出现在字符串的开头,并且任何行中数字之前没有任何内容,那么您可以使用:^(?![\d ]+)(lt[ .]*blue)

演示:https://regex101.com/r/sR18Rz/1

你的模式匹配 '4009 lt blue' 的原因是,在 l 之前,\s? 匹配空格零次并且 'l' 前面没有三个数字。

Regex 将尝试通过各种方式匹配您的模式,因此如果 \s 是可选的,它会尝试使用和不使用并保持匹配。在 4009 lt blue 的情况下,如果组中有 no space 则匹配(space 是 before群里,忽悠你的后视)。

由于后视在 python 中必须具有固定宽度,因此您不能将 \s? 添加到负向后视,但您仍然可以在另一个中处理这种情况:

(?<!\d{3})(?<!\d{3}\s)(lt\.?\s?blue)

作为替代方案,您可以使用 Pypi regex module 添加一个可选的 \s? 到后视,并且您可以仅省略匹配的捕获组。

import regex as re

pattern = r"(?<!\d\d\d\s?)lt\.?\s?blue\b"

s = ("ltblue\n"
"500lt.blue\n"
"4009 lt blue\n"
"lt. blue\n"
"032 lt red")

print(re.findall(pattern, s))

看到一个regex demo and a Python demo

输出

['ltblue', 'lt. blue']