Regex匹配2个重复值之间的所有值

Regex Matching everything between 2 repeating values

本文关键字:之间 匹配 2个 Regex      更新时间:2024-02-09

我正在制作一个提醒应用程序,我希望能够支持iCalender导入。这就是为什么我希望能够提取事件。这是iCalender:中事件的基本格式

BEGIN:VEVENT
......
......
END:VEVENT

所有这些事件都在一个文件中,所以我会有一个像这样的大列表:

BEGIN:VEVENT
......
......
END:VEVENT
BEGIN:VEVENT
......
......
END:VEVENT

这些事件将有一个开始日期和一个结束日期

BEGIN:VEVENT
......
DTSTART;VALUE=DATE:20160402
DTEND;VALUE=DATE:20160403
......
END:VEVENT

当试图仅提取事件时,它并不总是相同的格式。开始日期和结束日期可以在其他特定字段之前或之后。

目前我有:

/BEGIN:VEVENT['s'S]*?DTSTART;VALUE=DATE:20160402['s'S]*?END:VEVENT/

然而,这不仅仅与事件本身匹配,它从BEGIN:VEVENT的第一个匹配开始匹配,匹配到日期为止的所有内容,然后在下一个END:VEVENT完成匹配。

因此,在一些排名靠后的事件中,试图与之匹配的事件包括许多其他事件。有没有一种方法可以匹配DTSTART;VALUE=DATE:,只匹配上一个最近的BEGIN:VEVENT和下一个END:VEVENT,只提取当天的单个事件?

这个问题可以用一个经过回火的贪婪令牌来解决,该令牌可以用来获得文本中两个子字符串之间可能的最小窗口。由于文本是多行的,因此不能使用.原子来匹配任何字符,因此需要使用[^]['s'S]

所以,使用

/BEGIN:VEVENT((?:(?!'b(?:END|BEGIN):VEVENT'b)['s'S])*DTSTART;VALUE=DATE:20160402['s'S]*?)END:VEVENT/g

查看regex演示

(?:(?!'b(?:END|BEGIN):VEVENT'b)['s'S])*部分匹配不是BEGIN:VEVENTEND:VEVENT的任何文本(由于'b单词边界而作为整个单词)。

var re = /BEGIN:VEVENT((?:(?!'b(?:END|BEGIN):VEVENT'b)['s'S])*DTSTART;VALUE=DATE:20160402['s'S]*?)END:VEVENT/g; 
var str = 'BEGIN:VEVENT'n......'n......'nEND:VEVENT'nBEGIN:VEVENT'n......'n......'nEND:VEVENT'nThese events will have a start date and an end date'n'nBEGIN:VEVENT'n......'nDTSTART;VALUE=DATE:20160402'nDTEND;VALUE=DATE:20160403'n......'nEND:VEVENT';
var res = [];
 
while ((m = re.exec(str)) !== null) {
    res.push(m[0]);
}
document.body.innerHTML = "<pre>" + JSON.stringify(res.map(x => x.replace(/'r?'n/g, "<br/>")), 0, 4) + "</pre>";

请注意,['s'S]*?也可以替换为上述回火贪婪令牌,但似乎没有必要,因为VEVENT块是良好形式的,并且没有嵌套的VEVENT区块。如果存在嵌套的VEVENT块,则应将['s'S]*?替换为缓和贪婪令牌。