【问题标题】:VBA regex - match an expression that doesn't begin with a particular wordVBA 正则表达式 - 匹配不以特定单词开头的表达式
【发布时间】:2012-07-30 15:06:55
【问题描述】:

我正在寻找创建一个 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))

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

【问题讨论】:

  • 您可以去掉括号并调用Split 将条目分隔成一个可以搜索的数组吗?
  • 你不能只使用 InStr 函数吗?如果它在字符串中找到您要查找的短语的位置,您可以只使用布尔变量或其他东西并将其设置为 true 吗? InStr 函数在这里找到:msdn.microsoft.com/en-us/library/8460tsh1(v=vs.80).aspx
  • 我尽量回答你的问题,但你的问题定义不清楚。 a) 正则表达式永远不会有“匹配括号” 的概念。这在技术上是不可能的。 b) 您似乎认为, 是某种分隔符,但您从未真正定义过。

标签: regex vba


【解决方案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 出现在右括号之前

由于我使用了前瞻 ((?=...)),因此正则表达式引擎实际上从未在字符串上向前移动,因此我可以链接尽可能多的前瞻断言并检查它们。副作用是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,因为从技术上讲,aaa 和 xxx aaa 都在同一组括号内。
  • Regex 无法处理嵌套结构。你永远不会用正则表达式得到嵌套括号。您将永远无法仅使用正则表达式找到 “一组匹配的括号” - 只有一个中间没有其他括号的打开/关闭对。如果需要处理嵌套,请编写解析器。
  • 在您的项目中引用“Microsoft VBScript Regular Expressions 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

【讨论】:

  • 我会添加全局(参见下面的 tim williams 答案)并遍历所有匹配的术语。很有帮助,谢谢。
  • @JackBeNimble 将“global”添加到terms.Pattern 是没有意义的,因为它总是返回空字符串。
  • 好的,但是在函数的两次迭代中,上面的第二个测试用例对我来说都返回 false。不知道为什么,很难弄清楚这些表达方式。
  • @JackBeNimble 我认为这就是重点 - 第二个测试用例正是您在问题中遇到的那个,您说它应该返回 false。
【解决方案2】:

从你的问题中并不清楚你到底想要什么(也许这里真的不需要 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-23
    • 2010-11-17
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    相关资源
    最近更新 更多