RegEx 非贪婪量词 .*?没有按预期工作

RegEx non-greedy quantifier .*? not working as expected

我正在尝试创建一个正则表达式来匹配以下字符串中的“section 2 foo 2019 foo”(一个最小的例子,不是真实的):

section 1 bar bar section 2 foo 2019 foo section 3 bar 2021 bar end 

(字符串“section”,后跟数字,后跟任何文本,后跟 4 位数年份,再后跟任何文本)

我最初的想法是使用非贪婪量词和一个捕获组和一个非捕获组,如下所示:

(section [0-9]{1}.*?(19|20)[0-9]{2}.*?)(?:section)

但是,这将为捕获组生成以下匹配项:

section 1 bar section 2 foo 2019 foo

所以,它也匹配第 1 部分,我想排除它。

经过一些背景阅读,我明白这里的问题是“非贪婪”实际上并不意味着“匹配最短的字符串”,而是“匹配从左到右读取的最短的字符串”没有回溯。

关于这个问题,这里有一些关于 SO 的答案,但我仍在努力为这个特定案例找到正确的正则表达式。我尝试使用具有负前瞻性的非捕获组,如下所示:

section [0-9]{1,2}(?:(?!section [0-9]{1}).).*(?!202[1-9]{1})[0-9]{4} .*?

但是出乎意料的是,这仍然会匹配第一个不需要的部分。 知道我的想法可能哪里错了吗?

这里的问题是,对“任何”文本部分使用 .*? 仍然有可能匹配匹配或不匹配的部分,直到找到结束年份。您尝试使用调和点的最终正则表达式是在正确的轨道上。考虑这个版本:

\bsection \d+ (?:(?!\bsection \d+).)*?(?:19|20)\d{2}\b

Demo

解释:

\bsection \d+             match "section" followed by a number and space
(?:(?!\bsection \d+).)*?  match any content, without crossing over to another section
(?:19|20)\d{2}\b          match a 4 digit year