You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA正则匹配无括号MsgBox字符串字面量失败问题

问题说明

需要用VBA正则表达式检测工作簿模块中包含字符串字面量的MsgBox语句。当前pattern1可匹配带括号的MsgBox代码,但pattern2无法匹配无括号的目标代码;且匹配成功时match.SubMatches(0)返回空字符串。

pattern1 匹配成功示例

testString = MsgBox("Do you want to open our product page?", vbInformation + vbYesNoCancel, "myMessageBox")
testString = MsgBox("Do you want to open our product page?", vbYesNoCancel, "myMessageBox")
testString = MsgBox("Do you want to open our product page?", vbYesNoCancel)
testString = MsgBox("Do you want to open our product page?")

pattern2 目标匹配示例(当前无法匹配)

MsgBox "Do you want to open our product page?", vbInformation + vbYesNoCancel, "myMessageBox"
MsgBox "Do you want to open our product page?", vbInformation + vbYesNoCancel
MsgBox "Do you want to open our product page?"

现有检测代码

' Matches strings in all VBA modules of the specified workbook
' Add a reference to "Microsoft VBScript Regular Expressions 5.5" for early binding

Public Sub FindStringsInModules(ByVal objWorkbookToObfuscate As Workbook)
    Dim vbComp As Object
    Dim lineNum As Long
    Dim lineText As String
    Dim newLineText As String
    
    ' Iterate over all VBA modules in the provided workbook
    For Each vbComp In objWorkbookToObfuscate.VBProject.VBComponents
        ' Process each line in the module
        Dim lineCount As Long
        lineCount = vbComp.codeModule.CountOfLines
        For lineNum = 1 To lineCount
            lineText = vbComp.codeModule.Lines(lineNum, 1)
            newLineText = MatchLine(lineText)
            vbComp.codeModule.ReplaceLine lineNum, newLineText
        Next lineNum
    Next vbComp
End Sub

Function MatchLine(ByVal lineText As String) As String
    Dim regex As RegExp
    Set regex = New RegExp
    Dim pattern1 As String
    Dim pattern2 As String
    Dim pattern3 As String

    ' Pattern 1: Matches MsgBox with string literals, with opening and closing parenthesis ( )
    pattern1 = "(?:[a-zA-Z0-9]+\s*=\s*)?MsgBox\s*\(\s*(""[^""]*"")(?:\s*,\s*[^,)]+(?:\s*\+\s*[^,)]+)*)?(?:\s*,\s*""[^""]*"")?\s*\)"
    ' Pattern 2: Matches MsgBox without parentheses, including additional parameters and concatenations
    pattern2 = "MsgBox\s+""""[^""""""*""""""(?:\s*&\s*""""[^""""""*""""""|[^""""""])*(?:\s*,\s*[^,"""""]+)*"
    pattern3 = "MsgBox\(""[^""]*""\)\s*"

    ' Combine patterns using alternation operator
    regex.Pattern = pattern1 & "|" & pattern2 & "|" & pattern3
    regex.Global = True
    regex.MultiLine = True

    Dim matches As MatchCollection
    Set matches = regex.Execute(lineText)

    ' Process each match for potential transformation
    If matches.Count > 0 Then
        Dim match As match
        For Each match In matches
            Dim literal As String
            literal = match.SubMatches(0)
            If literal = "" Then
               Debug.Print "lineText not catched:" & lineText
               'Stop
            End If
        Next match
    End If

    MatchLine = lineText
End Function

注:在VBA中测试字符串字面量时,MsgBox语句需用双引号包裹,内部双引号需转义(如testString = "MsgBox ""Do you want to open our product page?""");测试代码行时则直接使用原始代码格式。

解决方案

问题分析

  1. pattern2语法错误:原pattern2中双引号转义逻辑混乱,导致正则无法正确识别VBA字符串字面量。
  2. 捕获组缺失:原pattern2未给字符串字面量添加捕获组,匹配成功时SubMatches(0)自然为空(仅pattern1有捕获组)。
  3. pattern3冗余:pattern3的匹配场景已被pattern1覆盖,无需单独保留。

修正后的正则模式

' Pattern 1: 带括号的MsgBox(含赋值/直接调用)
pattern1 = "(?:[a-zA-Z0-9_]+\s*=\s*)?MsgBox\s*\(\s*(""[^""]*"")(?:\s*,\s*(?:[^,)]+(?:\s*\+\s*[^,)]+)*|""[^""]*""))*\s*\)"
' Pattern 2: 不带括号的MsgBox(直接调用)
pattern2 = "MsgBox\s+(""[^""]*"")(?:\s*,\s*(?:[^,""]+(?:\s*\+\s*[^,""]+)*|""[^""]*""))*"
' 合并模式:带赋值的pattern1优先,避免被pattern2误匹配
regex.Pattern = pattern1 & "|" & pattern2

修正后的MatchLine函数

Function MatchLine(ByVal lineText As String) As String
    Dim regex As RegExp
    Set regex = New RegExp
    Dim pattern1 As String
    Dim pattern2 As String

    ' 修正后的正则模式
    pattern1 = "(?:[a-zA-Z0-9_]+\s*=\s*)?MsgBox\s*\(\s*(""[^""]*"")(?:\s*,\s*(?:[^,)]+(?:\s*\+\s*[^,)]+)*|""[^""]*""))*\s*\)"
    pattern2 = "MsgBox\s+(""[^""]*"")(?:\s*,\s*(?:[^,""]+(?:\s*\+\s*[^,""]+)*|""[^""]*""))*"
    
    regex.Pattern = pattern1 & "|" & pattern2
    regex.Global = True
    regex.MultiLine = True

    Dim matches As MatchCollection
    Set matches = regex.Execute(lineText)

    If matches.Count > 0 Then
        Dim match As match
        For Each match In matches
            Dim literal As String
            ' 检查两个捕获组,因为pattern1和pattern2的捕获组分别对应SubMatches(0)和SubMatches(1)
            If match.SubMatches(0) <> "" Then
                literal = match.SubMatches(0)
            ElseIf match.SubMatches(1) <> "" Then
                literal = match.SubMatches(1)
            End If
            
            If literal <> "" Then
                ' 此处可添加自定义处理逻辑(如替换字符串字面量)
                Debug.Print "捕获到字符串字面量: " & literal & " | 行内容: " & lineText
            Else
                Debug.Print "未捕获到有效字符串: " & lineText
            End If
        Next match
    End If

    MatchLine = lineText
End Function

修正要点

  • 修正pattern2的双引号转义,正确识别VBA字符串格式""[^""]*""。
  • 为pattern2添加捕获组,确保能提取目标字符串字面量。
  • 调整模式合并顺序,避免带赋值的MsgBox语句被pattern2误匹配。
  • 处理匹配结果时同时检查两个捕获组,兼容两种MsgBox写法的匹配结果。

内容的提问来源于stack exchange,提问作者Noam Brand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 11:10:56