正则表达式匹配 2 个重复值之间的所有内容
Regex Matching everything between 2 repeating values
我正在做一个提醒应用程序,我希望能够支持 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
结束匹配。 =19=]
因此,在一些事件中,试图匹配它们的列表还包括许多其他事件。有没有一种方法可以匹配 DTSTART;VALUE=DATE:
并且只匹配前一个最近的 BEGIN:VEVENT
和后面的 END:VEVENT
只是为了提取当天的单个事件?
这个问题可以用一个经过调节的贪婪标记来解决,它可以用来获得文本中两个子字符串之间可能的最小 window。由于您的文本是多行的,因此您不能使用 .
原子来匹配任何字符,您需要使用 [^]
或 [\s\S]
.
所以,使用
/BEGIN:VEVENT((?:(?!\b(?:END|BEGIN):VEVENT\b)[\s\S])*DTSTART;VALUE=DATE:20160402[\s\S]*?)END:VEVENT/g
(?:(?!\b(?:END|BEGIN):VEVENT\b)[\s\S])*
部分匹配任何非 BEGIN:VEVENT
和 END: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]*?
也可以用上面的 tempered greedy token 代替,但似乎没有必要,因为 VEVENT 块是良构的并且没有嵌套的 VEVENT 块。如果有嵌套的 VEVENT 块,[\s\S]*?
应该替换为 tempered greedy token。
我正在做一个提醒应用程序,我希望能够支持 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
结束匹配。 =19=]
因此,在一些事件中,试图匹配它们的列表还包括许多其他事件。有没有一种方法可以匹配 DTSTART;VALUE=DATE:
并且只匹配前一个最近的 BEGIN:VEVENT
和后面的 END:VEVENT
只是为了提取当天的单个事件?
这个问题可以用一个经过调节的贪婪标记来解决,它可以用来获得文本中两个子字符串之间可能的最小 window。由于您的文本是多行的,因此您不能使用 .
原子来匹配任何字符,您需要使用 [^]
或 [\s\S]
.
所以,使用
/BEGIN:VEVENT((?:(?!\b(?:END|BEGIN):VEVENT\b)[\s\S])*DTSTART;VALUE=DATE:20160402[\s\S]*?)END:VEVENT/g
(?:(?!\b(?:END|BEGIN):VEVENT\b)[\s\S])*
部分匹配任何非 BEGIN:VEVENT
和 END: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]*?
也可以用上面的 tempered greedy token 代替,但似乎没有必要,因为 VEVENT 块是良构的并且没有嵌套的 VEVENT 块。如果有嵌套的 VEVENT 块,[\s\S]*?
应该替换为 tempered greedy token。