如何使用行号自动填充 VBA 编辑器?

How can I automatically populate the VBA Editor with line numbers?

出于调试原因,我想在我的 VBA 代码中包含行号。这将使我知道特定错误发生的位置。

是否有自动功能(例如设置中的选项)?还是我需要自己写宏?

如果我需要编写自己的宏来完成此任务,我将如何着手做这样的事情?

我使用此代码向我的 Excel 项目添加行号。我不久前在网上找到它,但我不记得是从哪里得到的,所以感谢最初写这篇文章的人:

Sub AddLineNumbers(wbName As String, vbCompName As String)
    'See MakeUF
    Dim i As Long, j As Long, lineN As Long
    Dim procName As String
    Dim startOfProceedure As Long
    Dim lengthOfProceedure As Long
    Dim newLine As String

    With Workbooks(wbName).VBProject.VBComponents(vbCompName).CodeModule
        .CodePane.Window.Visible = False

        For i = 1 To .CountOfLines
            procName = .ProcOfLine(i, vbext_pk_Proc)

            If procName <> vbNullString Then
                startOfProceedure = .ProcStartLine(procName, vbext_pk_Proc)
                lengthOfProceedure = .ProcCountLines(procName, vbext_pk_Proc)

                If startOfProceedure + 1 < i And i < startOfProceedure + lengthOfProceedure - 1 Then
                    newLine = RemoveOneLineNumber(.Lines(i, 1))
                    If Not HasLabel(newLine) And Not (.Lines(i - 1, 1) Like "* _") Then
                        .ReplaceLine i, CStr(i) & ":" & newLine
                    End If
                End If
            End If

        Next i
        .CodePane.Window.Visible = True
    End With
End Sub

Sub RemoveLineNumbers(wbName As String, vbCompName As String)
    'See MakeUF
    Dim i As Long
    With Workbooks(wbName).VBProject.VBComponents(vbCompName).CodeModule
        For i = 1 To .CountOfLines
            .ReplaceLine i, RemoveOneLineNumber(.Lines(i, 1))
        Next i
    End With
End Sub

Function RemoveOneLineNumber(aString)
    RemoveOneLineNumber = aString
    If aString Like "#:*" Or aString Like "##:*" Or aString Like "###:*" Then
        RemoveOneLineNumber = Mid(aString, 1 + InStr(1, aString, ":", vbTextCompare))
    End If
End Function

Function HasLabel(ByVal aString As String) As Boolean
    HasLabel = InStr(1, aString & ":", ":") < InStr(1, aString & " ", " ")
End Function

由于您在 Access 中工作,因此您必须修改它以满足您的需要,但我相信它的主要内容仍然适用。在 Excel 中,有一个用户窗体用于为您指定的模块启动代码,但您应该能够只传入模块名称 (vbCompName) 来指定模块。我不太精通 Access VBA,所以我不确定您要用什么替换代码中的 Workbooks(wbName)

MZ-Tools for VBA 具有向单个函数、模块或整个项目添加和删除行号的功能。

http://www.mztools.com/v8/onlinehelp/index.html?add_remove_line_numbers.htm

注意 1:我发现将行号增量配置为 1 而不是 10 更好。您永远不会在两者之间手动添加行号 - 每当您编辑代码时,首先删除行号,然后再将它们添加回去当你完成时。

注2:直到几年前,还有免费的MZ-Tools 3.0版本,但出乎意料的难找。但这是一项很好的投资 - 还有许多其他有用的功能(例如,自动添加错误处理程序)。

这对我有用...将其添加到它自己的模块中。调用代码将打开或关闭行号。在引号中添加模块标题 and/or 过程标题将仅更新指定的模块或过程。

    Option Compare Database
    Option Explicit

    Sub AddLineNumbers(Optional vbCompName As String, Optional vbCompSubName As String)
    On Error Resume Next

        DoCmd.Hourglass True
        Application.VBE.ActiveVBProject.References.AddFromGuid "{0002E157-0000-0000-C000-000000000046}", 5, 0
        Call ExecuteAddLineNumbers(vbCompName, vbCompSubName)
        DoCmd.Hourglass False

    End Sub

    Sub ExecuteAddLineNumbers(Optional vbCompName As String, Optional vbCompSubName As String)
    On Error GoTo Err_Handler

        'create a reference to the Microsoft Visual Basic for Applications Extensibility library
        Dim i As Long, j As Long, lineN As Long
        Dim procName As String
        Dim startOfProceedure As Long
        Dim lengthOfProceedure As Long
        Dim newLine As String
        Dim objComponent As Object
        Dim lineNumber As Long
        Dim HasLineNumbers As Boolean

        For Each objComponent In Application.VBE.ActiveVBProject.VBComponents
            If (vbCompName = vbNullString Or objComponent.Name = vbCompName) And objComponent.Name <> _
            Application.VBE.ActiveCodePane.CodeModule.Name) Then
                Debug.Print objComponent.Name
                With objComponent.CodeModule
                    .CodePane.Window.Visible = False
                    For i = 1 To .CountOfLines
                        'Debug.Print .ProcOfLine(i, vbext_pk_Proc)
                        If procName = "" And .ProcOfLine(i, vbext_pk_Proc) <> "" Then
                            procName = .ProcOfLine(i, vbext_pk_Proc)
                            'vbext_pk_Get    Specifies a procedure that returns the value of a property.
                            'vbext_pk_Let    Specifies a procedure that assigns a value to a property.
                            'vbext_pk_Set    Specifies a procedure that sets a reference to an object.
                            'vbext_pk_Proc   Specifies all procedures other than property procedures.
                            'type=vbext_ct_ClassModule
                            'type=vbext_ct_StdModule
                            'type=vbext_ct_Document
                            If objComponent.Type = vbext_ct_ClassModule Then
                                If InStr(.Lines(i + 1, 1), " Let ") > 0 Then
                                    startOfProceedure = .ProcStartLine(procName, vbext_pk_Let)
                                    lengthOfProceedure = .ProcCountLines(procName, vbext_pk_Let)
                                ElseIf InStr(.Lines(i + 1, 1), " Get ") > 0 Then
                                    startOfProceedure = .ProcStartLine(procName, vbext_pk_Get)
                                    lengthOfProceedure = .ProcCountLines(procName, vbext_pk_Get)
                                ElseIf InStr(.Lines(i + 1, 1), " Set ") > 0 Then
                                    startOfProceedure = .ProcStartLine(procName, vbext_pk_Set)
                                    lengthOfProceedure = .ProcCountLines(procName, vbext_pk_Set)
                                Else
                                    startOfProceedure = .ProcStartLine(procName, vbext_pk_Proc)
                                    lengthOfProceedure = .ProcCountLines(procName, vbext_pk_Proc)
                                End If
                            Else
                                startOfProceedure = .ProcStartLine(procName, vbext_pk_Proc)
                                lengthOfProceedure = .ProcCountLines(procName, vbext_pk_Proc)
                            End If
                            lineNumber = 10
                            HasLineNumbers = .Find("##  ", startOfProceedure + 1, 1, startOfProceedure + lengthOfProceedure - 1, 1, _
                            False, False, True)
                        End If

                        If (vbCompSubName = vbNullString And procName <> vbNullString) Or _
                           (vbCompSubName <> vbNullString And procName = vbCompSubName) Then

                            If startOfProceedure + 1 < i And i < startOfProceedure + lengthOfProceedure - 1 Then
                                newLine = RemoveOneLineNumber(.Lines(i, 1), HasLineNumbers)
                                If Trim(newLine) <> vbNullString Then
                                    If Not HasLabel(newLine) And Not (.Lines(i - 1, 1) Like "* _") Then
                                        If HasLineNumbers = False Then newLine = CStr(lineNumber) & vbTab & newLine
                                        .ReplaceLine i, newLine
                                        lineNumber = lineNumber + 10
                                    ElseIf Not HasLineNumbers Then
                                        .ReplaceLine i, vbTab & newLine
                                    Else
                                        .ReplaceLine i, newLine
                                    End If
                                End If
                            ElseIf i = startOfProceedure + lengthOfProceedure - 1 Then
                                procName = ""
                            End If
                        Else
                            procName = ""
                        End If

                    Next i
                    .CodePane.Window.Visible = True
                End With
            End If
        Next objComponent

    Exit Sub

    Err_Handler:
        MsgBox (Err.Number & ": " & Err.Description)

    End Sub

    Function RemoveOneLineNumber(aString As String, HasLineNumbers As Boolean)
        Dim i As Double
        RemoveOneLineNumber = aString
        i = ((Len(Trim(Str(Val(aString)))) / 4) - Int(Len(Trim(Str(Val(aString)))) / 4)) * 4
        If aString Like "#*" Then
            RemoveOneLineNumber = Space(i) & Mid(aString, InStr(1, aString, " ", vbTextCompare))
            RemoveOneLineNumber = Right(aString, Len(aString) - 4)
        ElseIf HasLineNumbers And aString Like "    *" Then
            RemoveOneLineNumber = Right(aString, Len(aString) - 4)
        End If
    End Function

    Function HasLabel(ByVal aString As String) As Boolean
        HasLabel = False
        If Right(Trim(aString), 1) = ":" Or _
            Left(Trim(aString), 3) = "Dim" Or _
            Left(Trim(aString), 3) = "ReDim" Or _
            Left(Trim(aString), 1) = "'" Or _
            Left(Trim(aString), 6) = "Option" Or _
            Left(Trim(aString), 5) = "Debug" Or _
            Left(Trim(aString), 3) = "Sub" Or _
            Left(Trim(aString), 11) = "Private Sub" Or _
            Left(Trim(aString), 10) = "Public Sub" Or _
            Left(Trim(aString), 8) = "Function" Or _
            Left(Trim(aString), 12) = "End Function" Or _
            Left(Trim(aString), 8) = "Property" Or _
            Left(Trim(aString), 12) = "End Property" Or _
            Left(Trim(aString), 7) = "End Sub" Then HasLabel = True

    End Function

VBA 编辑器有一个内置的查看行号的方法,在 'Standard' 工具栏下:

当您 select 一行代码时,行号将显示在 'Ln' 旁边。

这未经过 100% 测试,但使用 VBA 可扩展性,您可以执行以下操作

Sub line_number(strModuleName As String)

Dim vbProj As VBProject
Dim vbComp As VBComponent
Dim cmCode As CodeModule
Dim intLine As Integer

Set vbProj = Application.VBE.ActiveVBProject
Set vbComp = vbProj.VBComponents(strModuleName)
Set cmCode = vbComp.CodeModule

For intLine = 2 To cmCode.CountOfLines - 1
   cmCode.InsertLines intLine, intLine - 1 &  cmCode.Lines(intLine, 1)
   cmCode.DeleteLines intLine + 1, 1
Next intLine

End Sub

前后效果如下,不推荐这样修改。

您不需要行号。

不是为了“调试原因”,不是为了任何事情。行号被弃用是有原因的:它们是远古时代的遗物,甚至还没有过程,而且 GOTO 是到达任何地方的唯一途径。

Erl 仅 returns 在引发错误之前最后遇到的行号 。如果您正在记录错误,这可能意味着误导性错误日志:

Sub DoSomething()
10 On Error GoTo 50
   Debug.Print 42 / 0
30 Exit Sub

50 Debug.Print "Error raised on line " & Erl 'returns 10
End Sub

此外,行号只有 Integer 分辨率(一个 VBA 模块最多可以有 65,535 行,是该分辨率的两倍),并且会默默地失败并愉快地报告错误的行号如果你没有记住这一点:

Sub DoSomething()
99997 On Error GoTo 99999
99998 Debug.Print 42 / 0
99999
      Debug.Print Erl   'Prints 34462 - and which line is that?
End Sub

任何严重的 VBA 应用程序都将使用 结构化错误处理

编写小型专用程序(即编写遵循现代最佳实践的代码),行号变得完全没有意义。

维护行号是件头疼的事;它们使代码变得混乱并使其整体更难阅读(因此更难调试)。


也就是说,IIRC MZ-Tools 3 具有这样的功能。

请记住,当行号是一回事时,BASIC 看起来像这样:

10 GOSUB 100
20 GOSUB 1000
99 END
100 REM CLEAR SCREEN
110 PRINT CHR$(147)
120 RETURN
200 REM MODULO
210 LET MOD% = V%-INT(V%/FB%)*FB%
220 RETURN
1000 REM INIT VARIABLES
1010 LET FIZZ$ = "FIZZ"
1011 LET BUZZ$ = "BUZZ"
1020 LET FIZZ% = 3
1021 LET BUZZ% = 5
1030 LET MIN% = 1
1031 LET MAX% = 15
1100 PRINT FIZZ$ + ":" + STR$(FIZZ%)
1101 PRINT BUZZ$ + ":" + STR(BUZZ%)
1102 PRINT FIZZ$ + BUZZ$ + ":" + STR$(FIZZ%*BUZZ%)
1105 PRINT
2000 REM ACTUAL FIZZBUZZ LOOP
2010 FOR X = MIN% TO MAX%
2015 LET RESULT$ = STR$(X)
2020 LET FB% = FIZZ%*BUZZ%
2021 LET V% = X
2024 GOSUB 200
2025 IF MOD%=0 THEN LET RESULT$=FIZZ$+BUZZ$ : GOTO 2050
2030 LET FB% = FIZZ%
2031 GOSUB 200
2035 IF MOD%=0 THEN LET RESULT$=FIZZ$ : GOTO 2050
2040 LET FB% = BUZZ%
2041 GOSUB 200
2045 IF MOD%=0 THEN LET RESULT$=BUZZ$ : GOTO 2050
2050 PRINT RESULT$
2090 NEXT X
2099 RETURN

以上是一个可用的 Commodore 64 BASIC 2.0 程序。 VBA 具有极好的向后兼容性。只需稍加修改,它就可以在 VBA:

中运行
Sub Main()
10     GoSub 100
20     GoSub 1000
99     End
100     Rem CLEAR SCREEN
110     'Debug.Print Chr$(147) 'Chr$(147) was a special character on C64
120     Return
200     Rem MODULO
210     Let Modulo% = V% - Int(V% / FB%) * FB%
220     Return
1000     Rem INIT VARIABLES
1010     Let FIZZ$ = "FIZZ"
1011     Let BUZZ$ = "BUZZ"
1020     Let FZZ% = 3
1021     Let BZZ% = 5
1030     Let Min% = 1
1031     Let Max% = 15
1100     Debug.Print FIZZ$ + ":" + Str$(FZZ%)
1101     Debug.Print BUZZ$ + ":" + Str(BZZ%)
1102     Debug.Print FIZZ$ + BUZZ$ + ":" + Str$(FZZ% * BZZ%)
1105     Debug.Print
2000     Rem ACTUAL FIZZBUZZ LOOP
2010     For X = Min% To Max%
2015     Let RESULT$ = Str$(X)
2020     Let FB% = FZZ% * BZZ%
2021     Let V% = X
2024     GoSub 200
2025     If Modulo% = 0 Then Let RESULT$ = FIZZ$ + BUZZ$: GoTo 2050
2030     Let FB% = FZZ%
2031     GoSub 200
2035     If Modulo% = 0 Then Let RESULT$ = FIZZ$: GoTo 2050
2040     Let FB% = BZZ%
2041     GoSub 200
2045     If Modulo% = 0 Then Let RESULT$ = BUZZ$: GoTo 2050
2050     Debug.Print RESULT$
2090     Next X
2099     Return
End Sub

不要写 1980 年代的代码,我们已经 40 年了。

Arich 的回答对单个模块很有用。如果您想为整个工作簿提供(更新的)行号,请执行以下步骤*^:

做一次:

  1. Module2 中的大代码粘贴到您的工作簿中。
  2. Module3 的代码粘贴到您的工作簿中。
  3. Module4 的代码粘贴到您的工作簿中。
  4. 然后粘贴行 Global allow_for_line_addition As String这只是为了让您可以自动添加行号` above/in 每个行的第一行 模块。
  5. 删除每个模块末尾的所有空行(因此在模块的最后一个 end subend functionEnd Property 之后不会输入 lose)。
  6. 在 VBA 编辑器中,虽然不是 运行 代码,也不处于 "break"-模式:单击工具>参考>标记:`Microsoft Visual Basic for Applications Extensibility 5.3

每次修改代码时做:

  1. °运行 Module3 的代码删除工作簿中所有模块的行号。
  2. °运行 Module4 的代码,用于向工作簿中的所有模块添加行号。

Module2:

    Public Enum vbLineNumbers_LabelTypes
        vbLabelColon    ' 0
        vbLabelTab      ' 1
    End Enum

    Public Enum vbLineNumbers_ScopeToAddLineNumbersTo
        vbScopeAllProc  ' 1
        vbScopeThisProc ' 2
    End Enum
              Sub AddLineNumbers(ByVal wbName As String, _
                                                          ByVal vbCompName As String, _
                                                          ByVal LabelType As vbLineNumbers_LabelTypes, _
                                                          ByVal AddLineNumbersToEmptyLines As Boolean, _
                                                          ByVal AddLineNumbersToEndOfProc As Boolean, _
                                                          ByVal Scope As vbLineNumbers_ScopeToAddLineNumbersTo, _
                                                          Optional ByVal thisProcName As String)

    ' USAGE RULES
    ' DO NOT MIX LABEL TYPES FOR LINE NUMBERS! IF ADDING LINE NUMBERS AS COLON TYPE, ANY LINE NUMBERS AS VBTAB TYPE MUST BE REMOVE BEFORE, AND RECIPROCALLY ADDING LINE NUMBERS AS VBTAB TYPE

        Dim i As Long
        Dim j As Long
        Dim procName As String
        Dim startOfProcedure As Long
        Dim lengthOfProcedure As Long
        Dim endOfProcedure As Long
        Dim strLine As String

        With Workbooks(wbName).VBProject.VBComponents(vbCompName).CodeModule
            .CodePane.Window.Visible = False

    If Scope = vbScopeAllProc Then

            For i = 1 To .CountOfLines - 1

                strLine = .Lines(i, 1)
                procName = .ProcOfLine(i, vbext_pk_Proc) ' Type d'argument ByRef incompatible ~~> Requires VBIDE library as a Reference for the VBA Project

                If procName <> vbNullString Then
                    startOfProcedure = .ProcStartLine(procName, vbext_pk_Proc)
                    bodyOfProcedure = .ProcBodyLine(procName, vbext_pk_Proc)
                    countOfProcedure = .ProcCountLines(procName, vbext_pk_Proc)

                    prelinesOfProcedure = bodyOfProcedure - startOfProcedure
                    'postlineOfProcedure = ??? not directly available since endOfProcedure is itself not directly available.

                    lengthOfProcedure = countOfProcedure - prelinesOfProcedure ' includes postlinesOfProcedure !
                    'endOfProcedure = ??? not directly available, each line of the proc must be tested until the End statement is reached. See below.

                    If endOfProcedure <> 0 And startOfProcedure < endOfProcedure And i > endOfProcedure Then
                        GoTo NextLine
                    End If

                    If i = bodyOfProcedure Then inprocbodylines = True

                    If bodyOfProcedure < i And i < startOfProcedure + countOfProcedure Then
                        If Not (.Lines(i - 1, 1) Like "* _") Then

                            inprocbodylines = False

                            PreviousIndentAdded = 0

                            If Trim(strLine) = "" And Not AddLineNumbersToEmptyLines Then GoTo NextLine

                            If IsProcEndLine(wbName, vbCompName, i) Then
                                endOfProcedure = i
                                If AddLineNumbersToEndOfProc Then
                                    Call IndentProcBodyLinesAsProcEndLine(wbName, vbCompName, LabelType, endOfProcedure)
                                Else
                                    GoTo NextLine
                                End If
                            End If

                            If LabelType = vbLabelColon Then
                                If HasLabel(strLine, vbLabelColon) Then strLine = RemoveOneLineNumber(.Lines(i, 1), vbLabelColon)
                                If Not HasLabel(strLine, vbLabelColon) Then
                                    temp_strLine = strLine
                                    .ReplaceLine i, CStr(i) & ":" & strLine
                                    new_strLine = .Lines(i, 1)
                                    If Len(new_strLine) = Len(CStr(i) & ":" & temp_strLine) Then
                                        PreviousIndentAdded = Len(CStr(i) & ":")
                                    Else
                                        PreviousIndentAdded = Len(CStr(i) & ": ")
                                    End If
                                End If
                            ElseIf LabelType = vbLabelTab Then
                                If Not HasLabel(strLine, vbLabelTab) Then strLine = RemoveOneLineNumber(.Lines(i, 1), vbLabelTab)
                                If Not HasLabel(strLine, vbLabelColon) Then
                                    temp_strLine = strLine
                                    .ReplaceLine i, CStr(i) & vbTab & strLine
                                    PreviousIndentAdded = Len(strLine) - Len(temp_strLine)
                                End If
                            End If

                        Else
                            If Not inprocbodylines Then
                                If LabelType = vbLabelColon Then
                                    .ReplaceLine i, Space(PreviousIndentAdded) & strLine
                                ElseIf LabelType = vbLabelTab Then
                                    .ReplaceLine i, Space(4) & strLine
                                End If
                            Else
                            End If
                        End If

                    End If

                End If

    NextLine:
            Next i

    ElseIf AddLineNumbersToEmptyLines And Scope = vbScopeThisProc Then

    End If

            .CodePane.Window.Visible = True
        End With

    End Sub
              Function IsProcEndLine(ByVal wbName As String, _
                  ByVal vbCompName As String, _
                  ByVal Line As Long) As Boolean

    With Workbooks(wbName).VBProject.VBComponents(vbCompName).CodeModule
    If Trim(.Lines(Line, 1)) Like "End Sub*" _
                Or Trim(.Lines(Line, 1)) Like "End Function*" _
                Or Trim(.Lines(Line, 1)) Like "End Property*" _
                Then IsProcEndLine = True
    End With

    End Function
              Sub IndentProcBodyLinesAsProcEndLine(ByVal wbName As String, ByVal vbCompName As String, ByVal LabelType As vbLineNumbers_LabelTypes, ByVal ProcEndLine As Long)
        Dim procName As String
        Dim startOfProcedure As Long
        Dim endOfProcedure As Long

        With Workbooks(wbName).VBProject.VBComponents(vbCompName).CodeModule

            procName = .ProcOfLine(ProcEndLine, vbext_pk_Proc)
            bodyOfProcedure = .ProcBodyLine(procName, vbext_pk_Proc)
            endOfProcedure = ProcEndLine
            strEnd = .Lines(endOfProcedure, 1)

            j = bodyOfProcedure
            Do Until Not .Lines(j - 1, 1) Like "* _" And j <> bodyOfProcedure

                strLine = .Lines(j, 1)

                If LabelType = vbLabelColon Then
                    If Mid(strEnd, Len(CStr(endOfProcedure)) + 1 + 1 + 1, 1) = " " Then
                        .ReplaceLine j, Space(Len(CStr(endOfProcedure)) + 1) & strLine
                    Else
                        .ReplaceLine j, Space(Len(CStr(endOfProcedure)) + 2) & strLine
                    End If
                ElseIf LabelType = vbLabelTab Then
                    If endOfProcedure < 1000 Then
                        .ReplaceLine j, Space(4) & strLine
                    Else
                        Debug.Print "This tool is limited to 999 lines of code to work properly."
                    End If
                End If

                j = j + 1
            Loop

        End With
    End Sub
              Sub RemoveLineNumbers(ByVal wbName As String, ByVal vbCompName As String, ByVal LabelType As vbLineNumbers_LabelTypes)
        Dim i As Long
        With Workbooks(wbName).VBProject.VBComponents(vbCompName).CodeModule
            'MsgBox ("nr of lines = " & .CountOfLines & vbNewLine & "Procname = " & procName)
                'MsgBox ("nr of lines REMEMBER MUST BE LARGER THAN 7! = " & .CountOfLines)
            For i = 1 To .CountOfLines
                procName = .ProcOfLine(i, vbext_pk_Proc)
                If procName <> vbNullString Then
                    If i > 1 Then
                            'MsgBox ("Line " & i & " is a body line " & .ProcBodyLine(procName, vbext_pk_Proc))
                        If i = .ProcBodyLine(procName, vbext_pk_Proc) Then inprocbodylines = True
                            If .Lines(i - 1, 1) <> "" Then
                                'MsgBox (.Lines(i - 1, 1))
                            End If
                        If Not .Lines(i - 1, 1) Like "* _" Then
                            'MsgBox (inprocbodylines)
                            inprocbodylines = False
                                'MsgBox ("recoginized a line that should be substituted: " & i)
                            'MsgBox ("about to replace " & .Lines(i, 1) & vbNewLine & " with: " & RemoveOneLineNumber(.Lines(i, 1), LabelType) & vbNewLine & " with label type: " & LabelType)
                            .ReplaceLine i, RemoveOneLineNumber(.Lines(i, 1), LabelType)
                        Else
                            If IsInProcBodyLines Then
                                ' do nothing
                                    'MsgBox (i)
                            Else
                                .ReplaceLine i, Mid(.Lines(i, 1), RemovedChars_previous_i + 1)
                            End If
                        End If
                    End If
                Else
                ' GoTo NextLine
                End If
    NextLine:
            Next i
        End With
    End Sub
              Function RemoveOneLineNumber(ByVal aString As String, ByVal LabelType As vbLineNumbers_LabelTypes)
        RemoveOneLineNumber = aString
        If LabelType = vbLabelColon Then
            If aString Like "#:*" Or aString Like "##:*" Or aString Like "###:*" Or aString Like "####:*" Then
                RemoveOneLineNumber = Mid(aString, 1 + InStr(1, aString, ":", vbTextCompare))
                If Left(RemoveOneLineNumber, 2) Like " [! ]*" Then RemoveOneLineNumber = Mid(RemoveOneLineNumber, 2)
            End If
        ElseIf LabelType = vbLabelTab Then
            If aString Like "#   *" Or aString Like "##  *" Or aString Like "### *" Or aString Like "#### *" Then RemoveOneLineNumber = Mid(aString, 5)
            If aString Like "#" Or aString Like "##" Or aString Like "###" Or aString Like "####" Then RemoveOneLineNumber = ""
        End If
    End Function
              Function HasLabel(ByVal aString As String, ByVal LabelType As vbLineNumbers_LabelTypes) As Boolean
        If LabelType = vbLabelColon Then HasLabel = InStr(1, aString & ":", ":") < InStr(1, aString & " ", " ")
        If LabelType = vbLabelTab Then
            HasLabel = Mid(aString, 1, 4) Like "#   " Or Mid(aString, 1, 4) Like "##  " Or Mid(aString, 1, 4) Like "### " Or Mid(aString, 1, 5) Like "#### "
        End If
    End Function
              Function RemoveLeadingSpaces(ByVal aString As String) As String
        Do Until Left(aString, 1) <> " "
            aString = Mid(aString, 2)
        Loop
        RemoveLeadingSpaces = aString
    End Function
              Function WhatIsLineIndent(ByVal aString As String) As String
        i = 1
        Do Until Mid(aString, i, 1) <> " "
            i = i + 1
        Loop
        WhatIsLineIndent = i
    End Function

              Function HowManyLeadingSpaces(ByVal aString As String) As String
        HowManyLeadingSpaces = WhatIsLineIndent(aString) - 1
    End Function

Module3:

    Global allow_for_line_addition As String 'this is just so that you can automatically add linenumbers
            Sub remove_line_numbering_all_modules()
    'source: 
    'This code numbers all the modules in your .xlsm
        Dim vbcomp As VBComponent
        Dim modules As Collection
    Set modules = New Collection
        For Each vbcomp In ThisWorkbook.VBProject.VBComponents
            'if normal or class module
            If ((vbcomp.Type = vbext_ct_StdModule) Or (vbcomp.Type = vbext_ct_ClassModule)) Then
                   'V0:
                   RemoveLineNumbers wbName:=ThisWorkbook.name, vbCompName:=vbcomp.name, LabelType:=vbLabelColon
                   'V1:
                   'Call RemoveLineNumbers(ThisWorkbook.name, vbcomp.name)
            End If
        Next vbcomp
    End Sub

Module4:

    Global allow_for_line_addition As String 'this is just so that you can automatically add linenumbers
    'This sub adds line numbers to all the modules after you have added the following line to every module
    'add tools references microsoft visual basic for applications (5.3) as checked
    'Source httpswhosebug.comquestions40731182excel-vba-how-to-turn-on-line-numbers-in-code-editor50368332#50368332
            Sub add_line_numbering_all_modules()
    'source: https://www.whosebug.com/questions/36791473/vba-getting-the-modules-in-workbook
    'This code numbers all the modules in your .xlsm
        Dim vbcomp As VBComponent
        Dim modules As Collection
        Set modules = New Collection
        For Each vbcomp In ThisWorkbook.VBProject.VBComponents
            'if normal or class module
            If ((vbcomp.Type = vbext_ct_StdModule) Or (vbcomp.Type = vbext_ct_ClassModule)) Then
                   'V0:
                   Call AddLineNumbers(ThisWorkbook.name, vbcomp.name, vbLabelColon, True, True, vbScopeAllProc)
                   'v1
                   'Call AddLineNumbers(ThisWorkbook.name, vbcomp.name)
            End If
        Next vbcomp
    End Sub

您可以将 "Book1.xlsm" 替换为您自己的工作簿的名称,或替换为 thisworkbook(注意没有“”),反之亦然。

  • *注意这在 excel 2016 年有效,我在 2013 年还没有尝试过。
  • ^它是 Hemced 的答案 here. 的修改版本,反过来看起来很像 Arich 的答案。
  • °因为有时如果您剪掉或移动它们(例如将 line 2440: 放在 line 2303: 上方),您会得到一个错误。通过删除并重新添加它们,行号将再次自动正确。

任何体面的错误处理程序都会报告不仅仅是行号。它将报告错误模式、描述和发生错误的模块。无论 ERL 是否在整个应用程序中重复行号,如果您无法通过报告的其他线索找到问题,也许您需要休假。或者,地狱,添加一个变量,该变量将模块级 alpha 代码递增作为行号的附件,如“newERL = strProcLevel & ERL”,为您提供“A12345”作为行号。