2016-04-06 78 views
1

我正在提醒应用程序,我希望能够支持iCalender导入。这就是为什么我想能够提取事件。这是一个事件的iCalender事件的基本格式:正则表达式匹配2个重复值之间的所有内容

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才能提取当天的单个事件?

+0

好吧,这里是 - https://regex101.com/r/oE6bB5/2 –

+0

不,我不能弄明白,我在正则表达式上很缺乏经验,哇,非常感谢! – danbeggan

回答

1

该问题可以通过一个脾气暴躁的标记来解决,该标记可用于获取文本中两个子字符串之间可能的最小窗口。由于您的文本是多行的,因此无法使用.原子来匹配任何字符,因此需要使用[^][\s\S]

因此,使用

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

the regex demo

(?:(?!\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]*?应该用缓和的贪婪标记代替。

+0

非常感谢你解释它,这是一个非常聪明的方式。因此,如果我理解了(?!\ b(?:END | BEGIN):VEVENT \ b),基本上是说如果我的BEGIN:VEVENT后面跟着END:VEVENT或BEGIN:VEVENT,而它们之间没有DTSTART则停止捕获? – danbeggan

+0

该标记与任何不是“BEGIN:VEVENT”和“END:VEVENT”的文本相匹配,直到第一个“DTSTART; VALUE = DATE:20160402”。因此,如果'DTSTART'在另一个VEVENT块中,则适当的'BEGIN:VEVENT'将被匹配。您可以在令牌的负向预览部分添加更多选项来替代'DTSTART',例如'(?!\ b(?:END | BEGIN):VEVENT \ b | DTSTART; VALUE = DATE: 20160402)' - 不确定它会工作得更快。 –

相关问题