Zero-width nhìn về phía trước asserttions là bạn của bạn.
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
mẫu này lần đọc như:
- Bắt đầu từ một dấu ngoặc mở, kiểm tra:
- rằng một paren khớp đóng cửa sau đâu đó và không có dấu ngoặc lồng nhau bên
- rằng
term1
xảy ra trước khi đóng paren
- rằng
term2
xảy ra trước khi đóng ngoặc đơn
Kể từ khi tôi đang sử dụng nhìn về phía trước ((?=...)
), động cơ regex bao giờ thực sự di chuyển về phía trước trên chuỗi, vì vậy tôi có thể chuỗi như nhiều khẳng định nhìn về phía trước và tất cả đều được kiểm tra.Một tác dụng phụ là thứ tự trong đó term1
và term2
xảy ra trong chuỗi không quan trọng.
Tôi đã thử nghiệm nó trên giao diện điều khiển ("Ngay lập tức cửa sổ"):
? 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
Ghi chú:
- Các thử nghiệm thứ hai sản lượng
True
vì-kỹ thuật-cả aaa
và xxx aaa
đang ở trong cùng một tập của parens.
- Regex không thể xử lý các cấu trúc lồng nhau. Bạn sẽ không bao giờ nhận được dấu ngoặc đơn lồng nhau ngay với các biểu thức thông thường. Bạn sẽ không bao giờ có thể tìm thấy "một tập hợp các dấu ngoặc đơn" chỉ với một mình regex - chỉ một cặp mở/đóng không có dấu ngoặc kép khác ở giữa. Viết một trình phân tích cú pháp nếu bạn cần xử lý lồng nhau.
- Tham chiếu đến "Microsoft VBScript Regular Expressions 5.5" trong dự án của bạn.
FWIW, đây là một chức năng làm tổ-aware tối thiểu mà làm việc cho các trường hợp thử nghiệm thứ hai ở trên:
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
Console:
? 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
Bạn có thể loại bỏ các dấu ngoặc đơn và gọi [ 'Split'] (http://msdn.microsoft.com/en-us/library/6x627e5f (v = vs.80) .aspx) để tách các mục nhập thành một mảng mà bạn có thể tìm kiếm? – mellamokb
bạn không thể sử dụng chức năng InStr cho điều này? Bạn chỉ có thể sử dụng một biến boolean hoặc một cái gì đó và đặt nó thành true nếu nó tìm thấy một vị trí cho cụm từ bạn đang tìm kiếm trong chuỗi? Chức năng InStr được tìm thấy tại đây: http://msdn.microsoft.com/en-us/library/8460tsh1(v=vs.80).aspx –
Tôi đã cố gắng trả lời câu hỏi của bạn tốt nhất có thể, nhưng bạn không rõ ràng trong định nghĩa vấn đề. ** a) ** Regex sẽ không bao giờ có khái niệm * "dấu ngoặc đơn phù hợp" *. Đó là kỹ thuật không thể. ** b) ** Bạn có vẻ giả định rằng ',' là một loại dấu tách, nhưng bạn không bao giờ thực sự xác định điều đó. – Tomalak