2012-07-30 10 views
5

Szukam utworzyć wyrażenie regularne VBA, które znajdzie istnienie dwóch określonych ciągów w zestawie nawiasów.Wyrażenie VBA - dopasowanie wyrażenia, które nie zaczyna się od określonego słowa

Na przykład w tym wyrażeniu:

(aaa, bbb, ccc, ddd, xxx aaa)

powinno jakoś mi powiedzieć, że uważamy, że zarówno "AAA" a "XXX AAA" w wyrażenie. I tak, ponieważ nie ma dopasowania na "aaa" bez "xxxx" z przodu, a jest też dopasowanie na "xxx aaa" później w wyrażeniu, powinno ono zwrócić wartość true. Ponieważ te dwie sekwencje mogą pojawić się w dowolnej kolejności, odwrotne powinno być również prawdziwe.

Więc myślę wyrażenia/s byłoby coś takiego:

"(xxx aaa" [^ x] [x ^] [^ x] [^ x] aaa) "

znaleźć słowa, w jednym zamówieniu oraz

"(AAA" [^ x] [^ x] [^ x] [^ x] XXX aaa)"

dla słów w innej kolejności.

Czy to ma sens? Czy istnieje lepsze podejście?

Wiem, że to zmienia specyfikację, ale jest jeden ważny dodatek - nie mogą występować żadne nawiasy między tymi terminami.

Tak na przykład, to should't pasuje:

(aaa, bbb, ccc, ddd (eee, xxx aaa))

Innymi słowy Próbuję spojrzeć pomiędzy pasujący zestaw tylko nawiasów.

+0

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

+0

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 –

+0

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

Odpowiedz

1

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 
+0

Dodałbym globalny (patrz odpowiedź tim williams poniżej) i przeglądaj wszystkie pasujące hasła. Bardzo pomocne, dzięki. –

+0

@JackBeNimble Dodawanie "global" do 'terms.Pattern' nie miałoby sensu, ponieważ zawsze zwraca pusty łańcuch. – Tomalak

+0

OK, ale drugi przypadek testowy powyżej zwraca dla mnie wartość false, zarówno w przypadku iteracji funkcji. Nie wiem dlaczego, trudno jest wyobrazić sobie wyrażenia. –

1

To naprawdę nie jest jasne, z pytaniem dokładnie, co chcesz (i być może Regexp nie jest naprawdę potrzebne tutaj), ale może to być blisko:

Sub Tester() 
    RegexpTest ("(aaa, bbb, ccc, ddd, xxx aaa)") 
End Sub 


Sub RegexpTest(txt As String) 
    Dim re As Object 
    Dim allMatches, m 

    Set re = CreateObject("VBScript.RegExp") 
    re.Pattern = "([^,\(]*aaa)" 
    re.ignorecase = True 
    re.Global = True 

    Set allMatches = re.Execute(txt) 

    For Each m In allMatches 
     Debug.Print Trim(m) 
    Next m 

End Sub 
Powiązane problemy