VBScript正则expression式填充子匹配,即使匹配不是必需的

我试图复制谷歌日历从叙述中创build约会的方法。 我想进入5pm Happy Hour for 1 hour并parsing它,最终,Outlook AppointmentItem。

我认为我的问题是我最后有一大段可选的文本。 而且因为它是可选的,正则expression式通过,但是不匹配子匹配,因为它不是必需的匹配。 我希望它填充,因为我想使用submatches作为我的parsing引擎。

我在A列中有一堆testing用例(在Excel中工作,然后移到Outlook),我的代码列出了右侧的子集。 这是潜在投入的代表性样本

 1. 5pmCST Happy Hour for 1 hour 2. 5pm CST Happy Hour for 1 hour 3. 5pm Happy Hour for 1 hour 4. 5 pm Happy Hour for 1 hour 5. 5 pm CST Happy Hour for 1 hour 6. 5 Happy Hour for 1 hour 7. 5 Happy Hour 8. 5pmCST Happy Hour 9. 5pm CST Happy Hour 10. 5pm Happy Hour 11. 5:00CST Happy Hour for 1 hour 12. 5:00 CST Happy Hour for 1 hour 

这是运行testing的代码

 Sub testest() Dim RegEx As VBScript_RegExp_55.RegExp Dim Matches As VBScript_RegExp_55.MatchCollection Dim Match As VBScript_RegExp_55.Match Dim rCell As Range Dim SubMatch As Variant Dim lCnt As Long Dim aPattern(1 To 8) As String Set RegEx = New VBScript_RegExp_55.RegExp aPattern(1) = "(1?[0-9](:[0-5][0-9])?)" 'time aPattern(2) = "( ?)" 'optional space aPattern(3) = "([ap]m)?" 'optional ampm aPattern(4) = "( ?)" 'optional space aPattern(5) = "([ECMP][DS]T)?" 'optional time zone aPattern(6) = "( ?)" 'optional space aPattern(7) = "(.+?)" 'event description aPattern(8) = "(( for )([1-2]?[0-9](.[0-9]?[0-9])?)( hours?))?" 'optional duration RegEx.Pattern = Join(aPattern, vbNullString) Debug.Print RegEx.Pattern Sheet1.Range("C1").Resize(1000, 100).ClearContents For Each rCell In Sheet1.Range("A1").CurrentRegion.Columns(1).Cells lCnt = 0 rCell.Offset(0, 2).Value = RegEx.test(rCell.Text) If RegEx.test(rCell.Text) Then Set Matches = RegEx.Execute(rCell.Text) For Each Match In Matches For Each SubMatch In Match.SubMatches lCnt = lCnt + 1 rCell.Offset(0, 2 + lCnt).Value = SubMatch Next SubMatch Next Match End If Next rCell End Sub 

模式是

 (1?[0-9](:[0-5][0-9])?)( ?)([ap]m)?( ?)([ECMP][DS]T)?( ?)(.+?)(( for )([1-2]?[0-9](.[0-9]?[0-9])?)( hours?))? 

#1的子匹配是

 1 2 3 4 5 6 7 5 pm CST H 

它在“欢乐时光”的“H”处停止匹配,因为以“for”开头的所有内容都是可选的。 如果我删除可选部分,我的模式变成

 (1?[0-9](:[0-5][0-9])?)( ?)([ap]m)?( ?)([ECMP][DS]T)?( ?)(.+?)( for )([1-2]?[0-9](.[0-9]?[0-9])?)( hours?) 

但#7 – #10没有通过,因为他们没有持续时间。 #1的submmatches给了我我想要的

 1 2 3 4 5 6 7 8 9 10 11 5 pm CST Happy Hour for 1 hour 

我希望每个可能的submatch填充,即使VBScript不需要它来进行正则expression式传递。 我担心这只是它的工作原理,而我正试图让正则expression式来为我做parsing工作。 我考虑通过越来越多的限制性模式来运行它,直到它不通过,然后使用最后通过的模式,但这似乎很烂。

是否有可能得到正则expression式来填补这些submatches?

我假定每行都是单个单元格中的所有内容。 所以我可以使用锚点。 我也不认为你需要像你一样多的捕捉组。 我设置了正则expression式:

 Group 1 Time Group 2 am/pm Group 3 Time Zone Group 4 Description Group 5 Hours (and fractions of hours) 

用A2:An中的数据,以下例程将数据parsing到相邻的列中。 Submatch是否“未填充”并不重要。 你也可以填充数组中的元素,或者任何你想做的事情。 如果您想要更多的子集,您可以随时为可选空格添加捕获组,也可以将相关的非捕获组更改为捕获组。

另外,由于“for”是可选的,我select使用前瞻来确定“description”的结束。 说明将以\ s + for \ s +序列结束; 或与“行尾”。 因为我假设每个单元只有一个入口和一行,所以多行和全局属性是不相关的。

必须在“for”之前和之后包含空格,以避免在Description中包含该序列的问题。

 Option Explicit 'set Reference to Microsoft VBScript Regular Expressions 5.5 Sub ParseAppt() Dim R As Range, C As Range Dim RE As RegExp, MC As MatchCollection Dim I As Long Set R = Range("a2", Cells(Rows.Count, "A").End(xlUp)) Set RE = New RegExp With RE .Pattern = "((?:1[0-2]|0?[1-9])(?::[0-5]\d)?)\s*([ap]m)?\s*([ECMT][DS]T)?\s*(.*?(?=\s+for\s+|$))(?:\s+for\s+(\d+(?:\.\d+)?)\s*hour)?" .IgnoreCase = True For Each C In R If .Test(C.Text) = True Then Set MC = .Execute(C.Text) For I = 0 To 4 C.Offset(0, I + 1) = MC(0).SubMatches(I) Next I End If Next C End With End Sub