5

括弧のセット内に2つの特定の文字列が存在することを検出するVBA正規表現を作成しようとしています。

たとえば、次の式では次のようになります。

(aaa、bbb、ccc、ddd、xxx aaa)

どういうわけか、式に「aaa」と「xxxaaa」の両方が見つかったことがわかります。つまり、前に「xxxx」がない「aaa」に一致があり、式の後半にある「xxx aaa」にも一致があるため、trueを返す必要があります。これらの2つのシーケンスはどちらの順序でも表示される可能性があるため、その逆も当てはまります。

したがって、式は次のようになると思います。

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

単語を1つの順序で検索し、

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

別の順序の単語のために。

これは意味がありますか?それとももっと良いアプローチがありますか?

これが仕様を変更していることは知っていますが、重要な補遺が1つあります。つまり、用語の間に括弧を挿入することはできません。

したがって、たとえば、これは一致しないはずです。

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

言い換えれば、私は一致する括弧のセットの間だけを調べようとしています。

4

2 に答える 2

1

あなたの質問からは、あなたが何を望んでいるのか正確には明確ではありません(そして、ここでは正規表現は本当に必要ないかもしれません)が、これは近いかもしれません:

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
于 2012-07-30T16:22:34.613 に答える
1

ゼロ幅の先読みアサーションはあなたの友達です。

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閉じ括弧の前にある

先読み ( (?=...)) を使用しているため、正規表現エンジンが実際に文字列を前方に移動することはありません。副作用として、文字列内でのterm1andterm2の出現順序は重要ではありません。

コンソールでテストしました(「イミディエイトウィンドウ」):

? 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
于 2012-07-30T17:20:02.777 に答える