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?""");测试代码行时则直接使用原始代码格式。
解决方案
问题分析
- pattern2语法错误:原pattern2中双引号转义逻辑混乱,导致正则无法正确识别VBA字符串字面量。
- 捕获组缺失:原pattern2未给字符串字面量添加捕获组,匹配成功时
SubMatches(0)自然为空(仅pattern1有捕获组)。 - 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
相关产品推荐
相关产品推荐

