zerowej szerokości asserttions antycypowana jest twoim przyjacielem.
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
Wzór ten brzmi:
- wychodząc z paren otwarcia sprawdzić:
- że paren dopasowanie zamknięcia następuje gdzieś i nie ma zagnieżdżone nawiasy wewnątrz
- że
term1
występuje przed zamykający paren
- , który
term2
występuje przed czytnikiem końcowym
Ponieważ używam look-ahead ((?=...)
), silnik regex nigdy nie porusza się do przodu na ciąg, więc mogę łańcucha tyle twierdzeń antycypowana i mieć je wszystkie sprawdzone.Efektem ubocznym jest to, że kolejność, w jakiej występują w łańcuchu, nie ma znaczenia.
Testowałem go na konsoli ("Natychmiastowe Okno"):
? 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
Uwagi:
- daje drugi test
True
bo-technicznie zarówno aaa
i xxx aaa
są wewnątrz tego samego zestawu z parens.
- Regex nie może obsługiwać struktur zagnieżdżonych. Nigdy nie otrzymasz zagnieżdżonych nawiasów w prawo za pomocą wyrażeń regularnych. Nigdy nie będziesz w stanie znaleźć "pasującego zestawu parenów" z samym regexem - tylko parę otwierającą/zamykającą, która nie ma innych parens pomiędzy. Napisz parser, jeśli potrzebujesz obsługi zagnieżdżania.
- Odwołanie do projektu "Microsoft VBScript Regular Expressions 5.5".
FWIW, oto minimalne funkcja zagnieżdżania-świadomość, że pracuje dla drugiego przypadku testowego powyżej:
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
konsoli:
? 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
można usunąć nawiasy i zadzwonić [ 'Split'] (http://msdn.microsoft.com/en-us/library/6x627e5f (v = vs.80) .aspx), aby oddzielić wpisy do tablicy, którą można przeszukać? – mellamokb
Nie możesz po prostu użyć do tego funkcji InStr? Możesz po prostu użyć zmiennej boolean lub czegoś podobnego i ustawić ją na true, jeśli znajdzie miejsce dla frazy, której szukasz w ciągu znaków? Funkcja InStr znajduje się tutaj: http://msdn.microsoft.com/en-us/library/8460tsh1(v=vs.80).aspx –
Starałem się odpowiedzieć na Twoje pytanie najlepiej, jak to możliwe, ale nie wiesz, definicja problemu. ** a) ** Regex nigdy nie będzie miał pojęcia * "pasujące nawiasy" *. To technicznie niemożliwe. ** b) ** Wydaje się, że zakładasz, że ',' jest rodzajem separatora, ale nigdy tak naprawdę nie definiujesz tego. – Tomalak