问题描述
我正在尝试创建一个正则表达式来匹配以下字符串中的“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 部分匹配。
经过一些背景阅读,我明白这里的问题是“非贪婪”实际上并不意味着“匹配可能最短的字符串”,而是意味着“从左到右匹配最短的可能字符串读取而不回溯”。
这里有一些关于这个问题的答案,但我仍在努力为这个特殊情况找到正确的正则表达式。我尝试使用具有负前瞻的非捕获组,如下所示:
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