5

我正在寻找创建一个 VBA 正则表达式,它将在一组括号内找到两个特定字符串的存在。

例如,在这个表达式中:

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

它应该以某种方式告诉我它在表达式中找到了“aaa”和“xxx aaa”。即,由于前面没有“xxxx”的“aaa”匹配,并且表达式后面的“xxx aaa”也有匹配,它应该返回true。由于这两个序列可以以任一顺序出现,因此反过来也应该是正确的。

所以我认为表达式/s会是这样的:

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

以一种顺序查找单词并且

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

换成另一个顺序的单词。

这有意义吗?还是有更好的方法?

我知道这正在改变规范,但有一个重要的附录 - 术语之间不能有任何中间括号。

例如,这不应该匹配:

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

换句话说,我试图只在一组匹配的括号之间查找。

4

2 回答 2

1

从你的问题中并不清楚你到底想要什么(也许这里真的不需要 Regexp),但这可能很接近:

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

这种模式读作:

  • 从一个开放的paren开始,检查:
    • 匹配的结束括号在某处后面,并且内部没有嵌套的括号
    • 发生term1在结束括号之前
    • 发生term2在结束括号之前

由于我使用了前瞻 ( (?=...)),因此正则表达式引擎实际上从未在字符串上向前移动,因此我可以链接尽可能多的前瞻断言并检查它们。副作用是字符串中出现的顺序term1无关紧要term2

我在控制台(“立即窗口”)上对其进行了测试:

? 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

笔记:

  • 第二个测试产生True,因为 - 从技术上讲 - 两者aaaxxx aaa在同一组括号内。
  • 正则表达式不能处理嵌套结构。你永远不会用正则表达式得到嵌套括号。仅使用正则表达式,您将永远无法找到“一组匹配的括号” - 只有一个中间没有其他括号的打开/关闭对。如果需要处理嵌套,请编写解析器。
  • 在您的项目中引用“Microsoft VBScript 正则表达式 5.5” 。

FWIW,这是一个最小的嵌套感知函数,适用于上面的第二个测试用例:

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 回答