零宽度前瞻断言是您的朋友。
Function FindInParen(str As String, term1 As String, term2 As String) As Boolean
Dim re As New VBScript_RegExp_55.RegExp
re.Pattern = "\(" & _
"(?=[^()]*)\)" & _
"(?=[^()]*\b" & RegexEscape(term1) & "\b)" & _
"(?=[^()]*\b" & RegexEscape(term2) & "\b)"
FindInParen = re.Test(str)
End Function
Function RegexEscape(str As String) As String
With New VBScript_RegExp_55.RegExp
.Pattern = "[.+*?^$|\[\](){}\\]"
.Global = True
RegexEscape = .Replace(str, "\$&")
End With
End Function
这种模式读作:
- 从一个开放的paren开始,检查:
- 匹配的结束括号在某处后面,并且内部没有嵌套的括号
- 发生
term1
在结束括号之前
- 发生
term2
在结束括号之前
由于我使用了前瞻 ( (?=...)
),因此正则表达式引擎实际上从未在字符串上向前移动,因此我可以链接尽可能多的前瞻断言并检查它们。副作用是字符串中出现的顺序term1
无关紧要term2
。
我在控制台(“立即窗口”)上对其进行了测试:
? FindInParen("(aaa, bbb, ccc, ddd, xxx aaa)", "aaa", "xxx aaa")
True
? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "aaa", "xxx aaa")
True
? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "bbb", "xxx aaa")
False
笔记:
- 第二个测试产生
True
,因为 - 从技术上讲 - 两者aaa
都xxx aaa
在同一组括号内。
- 正则表达式不能处理嵌套结构。你永远不会用正则表达式得到嵌套括号。仅使用正则表达式,您将永远无法找到“一组匹配的括号” - 只有一个中间没有其他括号的打开/关闭对。如果需要处理嵌套,请编写解析器。
- 在您的项目中引用“Microsoft VBScript 正则表达式 5.5” 。
FWIW,这是一个最小的嵌套感知函数,适用于上面的第二个测试用例:
Function FindInParen(str As String, term1 As String, term2 As String) As Boolean
Dim parenPair As New VBScript_RegExp_55.RegExp
Dim terms As New VBScript_RegExp_55.RegExp
Dim matches As VBScript_RegExp_55.MatchCollection
FindInParen = False
parenPair.Pattern = "\([^()]*\)"
terms.Pattern = "(?=.*?[(,]\s*(?=\b" & RegexEscape(Trim(term1)) & "\b))" & _
"(?=.*?[(,]\s*(?=\b" & RegexEscape(Trim(term2)) & "\b))"
Do
Set matches = parenPair.Execute(str)
If matches.Count Then
If terms.Test(matches(0).Value) Then
Debug.Print "found here: " & matches(0).Value
FindInParen = True
End If
str = parenPair.Replace(str, "[...]")
End If
Loop Until FindInParen Or matches.Count = 0
If Not FindInParen Then
Debug.Print "not found"
End If
If InStr("(", str) > 0 Or InStr(")", str) > 0 Then
Debug.Print "mis-matched parens"
End If
End Function
安慰:
? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "aaa", "xxx aaa")
not found
False
? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "eee", "xxx aaa")
found here: (eee, xxx aaa)
True