ゼロ幅の先読みアサーションはあなたの友達です。
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
このパターンは次のようになります。
- 開き括弧から始めて、次を確認します。
- 一致する閉じ括弧がどこかに続き、内部にネストされた括弧がないこと
term1
閉じ括弧の前にある
term2
閉じ括弧の前にある
先読み ( (?=...)
) を使用しているため、正規表現エンジンが実際に文字列を前方に移動することはありません。副作用として、文字列内でのterm1
andterm2
の出現順序は重要ではありません。
コンソールでテストしました(「イミディエイトウィンドウ」):
? 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
ノート:
- 2 番目のテストが成功するのは
True
、技術的には、aaa
との両方xxx aaa
が同じ括弧のセット内にあるためです。
- 正規表現は、ネストされた構造を処理できません。正規表現では、ネストされた括弧を正しく取得することはできません。正規表現だけでは「一致する括弧のセット」を見つけることはできません。間に他の括弧がない開始/終了のペアのみです。ネストを処理する必要がある場合は、パーサーを作成します。
- プロジェクトで「Microsoft VBScript Regular Expressions 5.5」への参照を作成します。
FWIW、上記の2番目のテストケースで機能する最小限のネスト対応関数は次のとおりです。
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