【问题标题】:How to check for empty array in vba macro [duplicate]如何检查vba宏中的空数组[重复]
【发布时间】:2025-12-18 21:45:01
【问题描述】:

我想检查空数组。谷歌给了我各种各样的解决方案,但没有奏效。也许我没有正确应用它们。

Function GetBoiler(ByVal sFile As String) As String
'Email Signature
    Dim fso As Object
    Dim ts As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
    GetBoiler = ts.ReadAll
    ts.Close
End Function

Dim FileNamesList As Variant, i As Integer
' activate the desired startfolder for the filesearch
FileNamesList = CreateFileList("*.*", False) ' Returns File names
' performs the filesearch, includes any subfolders
' present the result
' If there are Signatures then populate SigString
Range("A:A").ClearContents
For i = 1 To UBound(FileNamesList)
    Cells(i + 1, 1).Formula = FileNamesList(i)
Next i

SigString = FileNamesList(3)

If Dir(SigString) <> "" Then
    Signature = GetBoiler(SigString)
Else
    Signature = ""
End If

如果FileNamesList 数组为空,则根本不应该调用GetBoiler(SigString)。当FileNamesList 数组为空时,SigString 也为空,这将使用空字符串调用GetBoiler() 函数。我在

行遇到错误
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)

因为sFile 是空的。有什么办法可以避免吗?

【问题讨论】:

  • 查看modArraySupport,Chip Pearson 提供的一组有用的程序,用于支持处理数组。 IsArrayEmpty 做你想做的事。
  • If TypeName(FileNamesList) = "Empty" Then

标签: vba excel


【解决方案1】:

当你在处理一个字符串数组时,你考虑过Join吗?

If Len(Join(FileNamesList)) > 0 Then

【讨论】:

  • 是的,它很短。但它可能会做很多不必要的工作。
  • @VBOG 您想详细说明一下吗?
  • @Remou。 FileNamesList 不是数组吗?你不应该用 Ubound 代替 Len 吗?
  • @VBOG 不,因为 JOIN 刚刚从数组中创建了一个字符串。
  • 要注意的是,如果我有一个空字符串数组,这将不起作用......它并没有真正告诉我数组是否已初始化。
【解决方案2】:

三重否定:

If (Not Not FileNamesList) <> 0 Then
    ' Array has been initialized, so you're good to go.
Else
    ' Array has NOT been initialized
End If

或者只是:

If (Not FileNamesList) = -1 Then
    ' Array has NOT been initialized
Else
    ' Array has been initialized, so you're good to go.
End If

在 VB 中,无论出于何种原因,Not myArray 返回 SafeArray 指针。对于未初始化的数组,这将返回 -1。如果您愿意,您可以Not 将此与 -1 进行异或运算,从而返回零。

               (Not myArray)   (Not Not myArray)
Uninitialized       -1                 0
Initialized    -someBigNumber   someOtherBigNumber

Source

【讨论】:

  • 惊人的解决方案。从来不知道这个黑客。干杯!
  • 不错的技巧,我 +1,但不幸的是我不能将它用作函数的一部分,因为我得到运行时错误 13,类型不匹配Function isArrayInitialized2(Arr As Variant) As BooleanIf (Not Arr) = -1 Then isArrayInitialized2 = False Else isArrayInitialized2 = TrueEnd Function
  • @nkatsar 你需要将 Arr 作为 Arr() 传递
【解决方案3】:

如果您对数组函数进行测试,它将适用于所有范围:

Function IsVarArrayEmpty(anArray As Variant)

Dim i As Integer

On Error Resume Next
    i = UBound(anArray,1)
If Err.number = 0 Then
    IsVarArrayEmpty = False
Else
    IsVarArrayEmpty = True
End If

End Function

【讨论】:

  • 还不错,但在 arr 上试试吧,像这样定义 Dim arr() As String : arr = Split("") : Debug.Print IsVarArrayEmpty(arr)... 这会返回 False,但从所有人的角度来看,arr 奇怪的是,UBound(arr)=-1LBound(arr)=0 的空数组(或者其他人会怎么称呼它?)。 Chip Pearson 的IsArrayEmpty 处理了这个问题。这就是我在对问题的评论中链接到它的原因。
  • 遗憾的是有一个未定义的数组,当 UBound 抛出错误时。还有一个空数组,在任何其他情况下都可以找到长度:UBound(-1) - LBound(0) = 0
  • 您好,如果您在基数 0 上,您的数组可以添加一个索引 = 0 的元素。如果您不设置数组但如果您使用 redim arr(0) 则不会。在这种情况下,您的解决方案不起作用。您需要检查 Ubound(arr) = 0 和 len(Join(arr))=0。这是@BBQ Chef 回复的一部分
【解决方案4】:

我在这里看到类似的答案...但不是我的...

这就是我不幸的处理方式……我喜欢 len(join(arr)) > 0 方法,但如果数组是空字符串数组,它就行不通了……

Public Function arrayLength(arr As Variant) As Long
  On Error GoTo handler

  Dim lngLower As Long
  Dim lngUpper As Long

  lngLower = LBound(arr)
  lngUpper = UBound(arr)

  arrayLength = (lngUpper - lngLower) + 1
  Exit Function

handler:
  arrayLength = 0 'error occured.  must be zero length
End Function

【讨论】:

    【解决方案5】:

    写VBA的时候脑子里总有一句话:“本来可以这么简单,但是……”

    这是我采用它的目的:

    Private Function IsArrayEmpty(arr As Variant)
      ' This function returns true if array is empty
      Dim l As Long
    
      On Error Resume Next
      l = Len(Join(arr))
      If l = 0 Then
        IsArrayEmpty = True
      Else
        IsArrayEmpty = False
      End If
    
      If Err.Number > 0 Then
          IsArrayEmpty = True
      End If
    
      On Error GoTo 0
    End Function
    
    Private Sub IsArrayEmptyTest()
      Dim a As Variant
      a = Array()
      Debug.Print "Array is Empty is " & IsArrayEmpty(a)
      If IsArrayEmpty(a) = False Then
        Debug.Print "  " & Join(a)
      End If
    End Sub
    

    【讨论】:

    • 关于在汇编中检查数组是否为空的讨论比较简短。这太荒谬了。
    • @André Fratelli 我多么希望我能投票赞成你的评论
    【解决方案6】:

    这段代码没有达到你的预期:

    If Dir(SigString) <> "" Then
        Signature = GetBoiler(SigString) 
    Else
        Signature = "" 
    End If
    

    如果将空字符串("")或vbNullString 传递给Dir,它将返回当前目录路径中的第一个文件的名称(CurDir$ 返回的路径)。因此,如果SigString 为空,您的If 条件将评估为True,因为Dir 将返回一个非空字符串(当前目录中第一个文件的名称),而GetBoiler 将是叫。如果SigString 为空,则对fso.GetFile 的调用将失败。

    您应该更改条件以检查SigString 是否为空,或者使用FileSystemObject.FileExists 方法而不是Dir 来检查文件是否存在。 Dir 使用起来很棘手,因为它会做一些你可能没想到它会做的事情。就个人而言,我会使用Scripting.FileSystemObject 而不是Dir,因为没有什么有趣的事情(如果文件存在,FileExists 返回True,如果不存在,则返回False)。更重要的是,FileExistsDir 更清楚地表达了代码的意图

    方法一:先检查SigString是否为非空

    If SigString <> "" And Dir(SigString) <> "" Then
        Signature = GetBoiler(SigString) 
    Else
        Signature = "" 
    End If
    

    方法二:使用FileSystemObject.FileExists方法

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    If fso.FileExists(SigString) Then
        Signature = GetBoiler(SigString) 
    Else
        Signature = "" 
    End If
    

    【讨论】:

      【解决方案7】:

      我只是将伟大的 Chip Pearson 粘贴在代码下方。它很有魅力。
      这是他的page on array functions

      我希望这会有所帮助。

      Public Function IsArrayEmpty(Arr As Variant) As Boolean
      ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
      ' IsArrayEmpty
      ' This function tests whether the array is empty (unallocated). Returns TRUE or FALSE.
      '
      ' The VBA IsArray function indicates whether a variable is an array, but it does not
      ' distinguish between allocated and unallocated arrays. It will return TRUE for both
      ' allocated and unallocated arrays. This function tests whether the array has actually
      ' been allocated.
      '
      ' This function is really the reverse of IsArrayAllocated.
      '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
      
          Dim LB As Long
          Dim UB As Long
      
          err.Clear
          On Error Resume Next
          If IsArray(Arr) = False Then
              ' we weren't passed an array, return True
              IsArrayEmpty = True
          End If
      
          ' Attempt to get the UBound of the array. If the array is
          ' unallocated, an error will occur.
          UB = UBound(Arr, 1)
          If (err.Number <> 0) Then
              IsArrayEmpty = True
          Else
              ''''''''''''''''''''''''''''''''''''''''''
              ' On rare occasion, under circumstances I
              ' cannot reliably replicate, Err.Number
              ' will be 0 for an unallocated, empty array.
              ' On these occasions, LBound is 0 and
              ' UBound is -1.
              ' To accommodate the weird behavior, test to
              ' see if LB > UB. If so, the array is not
              ' allocated.
              ''''''''''''''''''''''''''''''''''''''''''
              err.Clear
              LB = LBound(Arr)
              If LB > UB Then
                  IsArrayEmpty = True
              Else
                  IsArrayEmpty = False
              End If
          End If
      
      End Function
      

      【讨论】:

      • RE:“在极少数情况下,在我无法可靠复制的情况下,对于未分配的空数组,Err.Number 将为 0”;当使用 arr=array() 生成一个空数组时会发生这种情况
      【解决方案8】:

      Auth 最接近,但他的回答引发类型不匹配错误。

      至于其他答案,如果可以的话,您应该避免使用错误来测试条件,因为至少它会使调试复杂化(如果其他原因导致该错误怎么办)。

      这是一个简单而完整的解决方案:

      option explicit
      Function foo() As Variant
      
          Dim bar() As String
      
          If (Not Not bar) Then
              ReDim Preserve bar(0 To UBound(bar) + 1)
          Else
              ReDim Preserve bar(0 To 0)
          End If
      
          bar(UBound(bar)) = "it works!"
      
          foo = bar
      
      End Function
      

      【讨论】:

        【解决方案9】:

        空数组的简化检查:

        Dim exampleArray() As Variant 'Any Type
        
        If ((Not Not exampleArray) = 0) Then
              'Array is Empty
        Else
              'Array is Not Empty
        End If
        

        【讨论】:

        • 这是我能在不捕获错误的情况下找到的唯一方法。难以置信。
        【解决方案10】:

        这是另一种方法。我在某些情况下使用过它并且它正在工作。

        Function IsArrayEmpty(arr As Variant) As Boolean
        
        Dim index As Integer
        
        index = -1
            On Error Resume Next
                index = UBound(arr)
            On Error GoTo 0
        
        If (index = -1) Then IsArrayEmpty = True Else IsArrayEmpty = False
        
        End Function
        

        【讨论】:

          【解决方案11】:

          基于ahuth的answer

          Function AryLen(ary() As Variant, Optional idx_dim As Long = 1) As Long
              If (Not ary) = -1 Then
                  AryLen = 0
              Else
                  AryLen = UBound(ary, idx_dim) - LBound(ary, idx_dim) + 1
              End If
          End Function
          

          检查一个空数组; is_empty = AryLen(some_array)=0

          【讨论】:

            【解决方案12】:
            Public Function IsEmptyArray(InputArray As Variant) As Boolean
            
               On Error GoTo ErrHandler:
               IsEmptyArray = Not (UBound(InputArray) >= 0)
               Exit Function
            
               ErrHandler:
               IsEmptyArray = True
            
            End Function
            

            【讨论】:

            • 如果你走这条路,你必须测试UBound &gt; LBound。在 VBA 中,您可以运行数组索引,例如 -5321 To -4112。这只是该语言的“有趣”怪癖之一。
            【解决方案13】:

            您可以使用下面的函数来检查 vba 中的变量或字符串数​​组是否为空

            Function IsArrayAllocated(Arr As Variant) As Boolean
                    On Error Resume Next
                    IsArrayAllocated = IsArray(Arr) And _
                                       Not IsError(LBound(Arr, 1)) And _
                                       LBound(Arr, 1) <= UBound(Arr, 1)
            End Function
            

            示例用法

            Public Function test()
            Dim Arr(1) As String
            Arr(0) = "d"
            Dim x As Boolean
            x = IsArrayAllocated(Arr)
            End Function
            

            【讨论】:

              【解决方案14】:

              另一种方法是尽早完成。将数据加载到数组后,您可以创建一个布尔变量并将其设置为 true。因此,您真正需要的只是一个简单的 if 语句,说明何时将数据加载到数组中。

              【讨论】:

                【解决方案15】:

                要检查一个Byte数组是否为空,最简单的方法是使用VBA函数StrPtr()

                如果Byte数组为空,StrPtr()返回0;否则,它返回一个非零值(但是,它不是第一个元素的地址)。

                Dim ar() As Byte
                Debug.Assert StrPtr(ar) = 0
                
                ReDim ar(0 to 3) As Byte
                Debug.Assert StrPtr(ar) <> 0
                

                但是,它只适用于字节数组。

                【讨论】:

                  【解决方案16】:
                  Function IsVarArrayEmpty(anArray As Variant) as boolean
                      On Error Resume Next
                      IsVarArrayEmpty = true
                      IsVarArrayEmpty = UBound(anArray) < LBound(anArray)
                  End Function
                  

                  也许ubound 崩溃并且它保持为真,如果ubound &lt; lbound 则为空

                  【讨论】:

                    【解决方案17】:

                    我将按预期概括问题和问题。 对数组进行测试,捕获最终的错误

                    Function IsVarArrayEmpty(anArray as Variant)
                    Dim aVar as Variant
                    
                    IsVarArrayEmpty=False
                    On error resume next
                    aVar=anArray(1)
                    If Err.number then '...still, it might not start at this index
                        aVar=anArray(0)
                        If Err.number then IsVarArrayEmpty=True ' neither 0 or 1 yields good assignment
                    EndIF
                    End Function
                    

                    确定它错过了所有负索引或所有 > 1 的数组...这可能吗?在奇怪的地方,是的。

                    【讨论】:

                    • 如果它在奇异世界中不起作用,那么它就不是“通用的”。
                    【解决方案18】:

                    我个人认为可以修改上面的答案之一来检查数组是否有内容:

                    if UBound(ar) > LBound(ar) Then
                    

                    这处理负数引用并且比其他一些选项花费更少的时间。

                    【讨论】:

                    • 未分配数组(不是ReDimed)以及恰好只有一个元素的数组失败。这也是这个问题的其他(不正确)答案的抄袭?
                    【解决方案19】:

                    您可以通过使用 JScript 的 VBArray() 对象检索总元素计数来检查数组是否为空(适用于变体类型的数组,单维或多维):

                    Sub Test()
                    
                        Dim a() As Variant
                        Dim b As Variant
                        Dim c As Long
                    
                        ' Uninitialized array of variant
                        ' MsgBox UBound(a) ' gives 'Subscript out of range' error
                        MsgBox GetElementsCount(a) ' 0
                    
                        ' Variant containing an empty array
                        b = Array()
                        MsgBox GetElementsCount(b) ' 0
                    
                        ' Any other types, eg Long or not Variant type arrays
                        MsgBox GetElementsCount(c) ' -1
                    
                    End Sub
                    
                    Function GetElementsCount(aSample) As Long
                    
                        Static oHtmlfile As Object ' instantiate once
                    
                        If oHtmlfile Is Nothing Then
                            Set oHtmlfile = CreateObject("htmlfile")
                            oHtmlfile.parentWindow.execScript ("function arrlength(arr) {try {return (new VBArray(arr)).toArray().length} catch(e) {return -1}}"), "jscript"
                        End If
                        GetElementsCount = oHtmlfile.parentWindow.arrlength(aSample)
                    
                    End Function
                    

                    对我来说,每个元素大约需要 0.3 mksec + 15 msec 初始化,因此 10M 个元素的数组大约需要 3 sec。相同的功能可以通过ScriptControl ActiveX 实现(它在 64 位 MS Office 版本中不可用,因此您可以使用类似this 的解决方法)。

                    【讨论】:

                    【解决方案20】:
                    if Ubound(yourArray)>-1 then
                     debug.print "The array is not empty"
                    else
                     debug.print "EMPTY"
                    end if
                    

                    【讨论】:

                      【解决方案21】:

                      您可以查看它的计数。

                      这里 cid 是一个数组。

                      if (jsonObject("result")("cid").Count) = 0 them
                      MsgBox "Empty Array"
                      

                      我希望这会有所帮助。 祝你有美好的一天!

                      【讨论】:

                        【解决方案22】:

                        另一种测试空数组的解决方案

                        if UBound(ar) < LBound(ar) then msgbox "Your array is empty!"
                        

                        或者,如果你已经知道 LBound 是 0

                        if -1 = UBound(ar) then msgbox "Your array is empty!"
                        

                        这可能比 join() 更快。 (而且我没有检查负索引)

                        这是我过滤 2 个字符串数组的示例,以便它们不共享相同的字符串。

                        ' Filtering ar2 out of strings that exists in ar1
                        
                        For i = 0 To UBound(ar1)
                        
                            ' filter out any ar2.string that exists in ar1
                            ar2 = Filter(ar2 , ar1(i), False)    
                        
                            If UBound(ar2) < LBound(ar2) Then
                               MsgBox "All strings are the same.", vbExclamation, "Operation ignored":
                               Exit Sub
                        
                            End If
                        
                        Next
                        
                        ' At this point, we know that ar2 is not empty and it is filtered 
                        '
                        

                        【讨论】:

                        • 如果数组为空,UBound 将失败,它不会返回 -1 或 1-less-than-lbound
                        【解决方案23】:
                        Public Function arrayIsEmpty(arrayToCheck() As Variant) As Boolean
                            On Error GoTo Err:
                            Dim forCheck
                            forCheck = arrayToCheck(0)
                            arrayIsEmpty = False
                            Exit Function
                        Err:
                            arrayIsEmpty = True
                        End Function
                        

                        【讨论】:

                        • 非零基数组失败,例如ReDim arrayToCheck(1 To 10).