淘先锋技术网

首页 1 2 3 4 5 6 7

Office自带的VBE在编辑代码时,没有自动完成代码缩进的功能,而我们在网上找到的VBA代码,经常没有实现良好的自动缩进,复制到VBE后,可读性较差。本文介绍的宏,通过使用vbscript.regexp对象,利用正则表达式匹配VBA 代码块中开始和结束关键字,完成缩进量的计算,从而实现VBA代码的格式化。
要使用vbscript.regexp对象,需要用过VBE的“工具”菜单的“引用”命令引入Microsoft VBScript Regular Expressions 5.5这个库。引入这个库后,我们构筑三个正则表达式,分别匹配VBA代码块的开始记号、结束记号及中继记号。例如一个If-Else-End If代码块,If就是这个代码块的开始记号,遇到了开始记号,下面的行就需要增加一个缩进单位;Else就是这个代码块的中继记号,遇到中继记号,不影响后续行的缩进,但本行的缩进需要减少一个单位;End If就是这个代码块的结束记号,遇到结束记号,本行和后续各行的缩进量就要减少一个单位。此外还有一个特殊情况,就是换行连接符“_”,其后续第一行也宜增加一个缩进量,如果下一行仍然太长被分行,则再下面一行不用继续增加缩进。
宏代码如下,运行宏前需先选择复制到Word文档中的整个代码块。如果所选择的代码中包含的所有代码块结构完整,则所选择的代码块被替换为缩进规范的代码。如运行宏后发现代码缩进不正确,则代码中肯定有错误,存在结构不完整的代码块。

Sub VBA代码缩进()
    Dim aPara As Paragraph
    Dim CumulativeIndent As Integer, currParaIndent%, i%
    Dim sTmp As String, sResult$
    
    Dim regRight As RegExp, regLeft As RegExp, regMiddle As RegExp
    
    Set regRight = CreateObject("vbscript.regexp")
    Set regLeft = CreateObject("vbscript.regexp")
    Set regMiddle = CreateObject("vbscript.regexp")
    
 
    'regLeft匹配需要增加后续段落左缩进的段落,即段落开头为代码块开始记号的段落
    'if语句比较特殊,有些整个结构在一行结束,有些需要end if结束,
    '区别在于then是不是在行末最后的非空白字符
    With regLeft
        .Pattern = "(^(for|while|with|do|select|((public|private)\s)*(sub|function))\s)|(^(if|#if)\s+\S.*\sthen\s{0,}$)"
        .IgnoreCase = True
        .MultiLine = True
    End With
    'regRight匹配需要减少本段及后续段落左缩进的段落,即段落开头为代码块结束记号的段落
    regRight.Pattern = "^(end\s|#end\s|loop|next|wend)"
    regRight.IgnoreCase = True
    'regMiddle匹配对前后段落缩进没有影响,但需要减少本段左缩进的段落,即段落开头为中继记号的段落
    regMiddle.Pattern = "^(elseif|else|#elseif|#else|case)\s"
    regMiddle.IgnoreCase = True
    '将所选择的代码原有不规范的缩进全部删除,即替换掉各段前导空格或制表符(^t),以免影响最终缩进
    '将过多的记号之间的空白替换为1个空格。
    With Selection.Find
        .MatchWildcards = True
        .Execute FindText:="^13[ ^t]{1,}", _
            ReplaceWith:="^p", Replace:=wdReplaceAll
        .Execute FindText:="[ ^t]{2,}", _
            ReplaceWith:=" ", Replace:=wdReplaceAll
    End With
    '记录一行代码前累计需添加的缩进量
    CumulativeIndent = 0
    For Each aPara In Selection.Paragraphs
        '将当前段落文本读入临时字符串,去掉前后空白
        sTmp = Trim(aPara.Range.Text)
        '计算缩进量
        '遇到代码块开始记号,左缩进增加1(注意本段增加的缩进后面需要减掉)
        If regLeft.test(sTmp) Then
            CumulativeIndent = CumulativeIndent + 1
        '遇到代码块结束记号,左缩进减少1
        ElseIf regRight.test(sTmp) Then
            CumulativeIndent = CumulativeIndent - 1
        End If
        
        '计算本段的段落缩进,如果本段为代码块开始记号或者是中间记号开头,
        '需要将本段前面加上的缩进量调整回去
        If regLeft.test(sTmp) Or regMiddle.test(sTmp) Then
            currParaIndent = CumulativeIndent - 1
        Else
            currParaIndent = CumulativeIndent
        End If
        '根据需要添加的缩进量,在本段文本前添加TAB(Chr(9))
        For i = 1 To currParaIndent
            sTmp = Chr(9) & sTmp
        Next
        '如果上一行末尾是换行连接符,下一行增加一个TAB进行缩进
        '由于没有修改CumulativeIndent,所以这个操作不会影响其他行的缩进量 
        If Right(sResult, 2) = "_" & Chr(13) Then
            sTmp = Chr(9) & sTmp
        End If
        '将添加了TAB的字符串拼接到结果字符串中
        sResult = sResult & sTmp
    Next
    Selection.Text = Replace(sResult, Chr(13) & Chr(13), Chr(13))
End Sub