2016-04-06 93 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)' - 不確定它會工作得更快。 –

相關問題