如何在vba宏中检查空数组

时间:2008-10-15 20:31:21

标签: excel vba excel-vba

我想检查空数组。 Google给了我各种解决方案,但没有任何效果也许我没有正确应用它们。

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为空。有什么办法可以避免吗?

23 个答案:

答案 0 :(得分:73)

在处理字符串数组时,您考虑过加入吗?

If Len(Join(FileNamesList)) > 0 Then

答案 1 :(得分:61)

使用三重否定:

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

答案 2 :(得分:28)

如果你测试一个数组函数,它将适用于所有边界:

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

答案 3 :(得分:6)

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

这就是我不幸要处理它的方式......我喜欢len(join(arr))&gt; 0方法,但如果数组是一个emptystrings数组,它将无法工作......

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

答案 4 :(得分: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

答案 5 :(得分:4)

此代码无法满足您的期望:

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

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

您应该更改条件以检查fso.GetFile是否为空,或使用SigString方法而不是FileSystemObject.FileExists来检查文件是否存在。 Dir使用起来很棘手,因为它可以做你可能不希望它做的事情。就个人而言,我会使用Dir而不是Scripting.FileSystemObject,因为没有有趣的商家(如果文件存在,Dir会返回FileExists,如果不存在,True “T)。更重要的是,FalseFileExists更清楚地表达了代码的 intent

方法1:检查Dir是否为非空首

SigString

方法2:使用If SigString <> "" And Dir(SigString) <> "" Then Signature = GetBoiler(SigString) Else Signature = "" End If 方法

FileSystemObject.FileExists

答案 6 :(得分:4)

我只是简单地粘贴在伟大的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

答案 7 :(得分:2)

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

答案 8 :(得分:2)

基于ahuth&#39; 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

答案 9 :(得分:2)

简化检查空数组:

Dim exampleArray() As Variant 'Any Type

If ((Not Not exampleArray) = 0) Then
      'Array is Empty
Else
      'Array is Not Empty
End If

答案 10 :(得分:1)

Public Function IsEmptyArray(InputArray As Variant) As Boolean

   On Error GoTo ErrHandler:
   IsEmptyArray = Not (UBound(InputArray) >= 0)
   Exit Function

   ErrHandler:
   IsEmptyArray = True

End Function

答案 11 :(得分:1)

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

答案 12 :(得分:1)

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

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

答案 13 :(得分:1)

Function IsVarArrayEmpty(anArray As Variant) as boolean
    On Error Resume Next
    IsVarArrayEmpty = true
    IsVarArrayEmpty = UBound(anArray) < LBound(anArray)
End Function

也许ubound崩溃并且仍然是真的,如果ubound < lbound,它就是空的

答案 14 :(得分:1)

要检查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

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

答案 15 :(得分:0)

就个人而言,我认为可以修改上述答案之一以检查数组是否包含内容:

if UBound(ar) > LBound(ar) Then

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

答案 16 :(得分:0)

您可以使用以下函数检查变量或字符串数​​组在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

答案 17 :(得分:0)

您可以使用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毫秒初始化,因此10M元素阵列大约需要3秒。可以通过ScriptControl ActiveX实现相同的功能(它在64位MS Office版本中不可用,因此您可以使用this之类的解决方法。

答案 18 :(得分:0)

if Ubound(yourArray)>-1 then
 debug.print "The array is not empty"
else
 debug.print "EMPTY"
end if

答案 19 :(得分:0)

我会按预期概括问题和问题。 测试数组上的assing,并捕获最终的错误

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

当然它错过了所有负面索引的数组或全部&gt; 1 ......可能吗?在古怪的地方,是的。

答案 20 :(得分:0)

您可以检查其计数。

此处 cid 是一个数组。

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

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

答案 21 :(得分:-1)

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

答案 22 :(得分:-1)

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

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 
'