如何检查vbamacros中的空数组

我想检查空数组。 谷歌给了我不同的解决scheme,但没有奏效 也许我没有正确应用它们。

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也是空的,这将调用带有空string的GetBoiler()函数。 我得到一个错误在线

 Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2) 

因为sFile是空的。 任何方法来避免这种情况?

正如你正在处理一个string数组,你有没有考虑join?

 If Len(Join(FileNamesList)) > 0 Then 

去三重否定:

 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中,不pipe什么原因, Not myArray返回SafeArray指针。 对于未初始化的数组,这将返回-1。 你不能用-1来异或,如果你愿意,返回零。

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

资源

如果你testing一个数组函数,它将适用于所有的界限:

 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 

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

这是我如何不幸处理它…我喜欢len(join(arr))> 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 

在写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 

我只是简单地粘贴在伟大的Chip Pearson的代码之下。 它的魅力。
这是他关于数组函数的页面 。

我希望这有帮助。

 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 

这段代码并不符合你的期望:

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

如果将空string( "" )或vbNullString传递给Dir ,它将返回当前目录path(由CurDir$返回的path)中的第一个文件的名称。 因此,如果SigString为空, If条件将计算为True因为Dir将返回非空string(当前目录中的第一个文件的名称),并GetBoiler 。 如果SigString为空,则调用fso.GetFile将失败。

您应该更改您的条件,以检查SigString是否为空,或使用FileSystemObject.FileExists方法而不是Dir检查文件是否存在。 Dir很难正确使用,因为它可以做你可能不期望的事情。 就个人而言,我会在Dir使用Scripting.FileSystemObject ,因为没有有趣的事情(如果文件存在, FileExists返回True如果不存在则返回False )。 更重要的是, FileExistsDir更清楚地expression你的代码的意图

方法1:首先检查SigString非空

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

方法2:使用FileSystemObject.FileExists方法

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

authentication是最接近的,但他的答案抛出types不匹配的错误。

至于其他的答案,你应该避免使用一个错误来testing一个条件,如果可以的话,因为最起码它会使debugging变得复杂(如果其他东西导致了这个错误)。

这是一个简单,完整的解决scheme:

 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 

简化空arrays检查:

 Dim exampleArray() As Variant 'Any Type If ((Not Not exampleArray) = 0) Then 'Array is Empty Else 'Array is Not Empty End If 
 Public Function IsEmptyArray(InputArray As Variant) As Boolean On Error GoTo ErrHandler: IsEmptyArray = Not (UBound(InputArray) >= 0) Exit Function ErrHandler: IsEmptyArray = True End Function 

这是另一种方式来做到这一点。 我曾经在一些情况下使用过它,它正在工作。

 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 

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

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

我将按照预期概括问题和问题。 对arrays进行testing确认,并捕获最终的错误

 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 …是否有可能? 在怪人,是的。

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

 if UBound(ar) > LBound(ar) Then 

这处理负数参考和比其他一些选项花费更less的时间。

你可以使用下面的函数来检查vba中variables或string数​​组是否为空

 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 

另一种方法是尽早做到这一点。 一旦将数据加载到数组中,您可以创build一个布尔variables并将其设置为true。 所以你真正需要的只是一个简单的if语句,当你将数据加载到数组中的时候。

你可以通过使用JScript的VBArray()对象(用于variablestypes的数组,单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 

对我来说,每个元素+ 15毫秒的初始化需要大约0.3毫秒,所以10M元素的arrays需要大约3秒。 可以通过ScriptControl ActiveX实现相同的function(它不适用于64位MS Office版本,因此您可以使用这种解决方法)。

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

==>也许ubound崩溃,它仍然是真实的,如果ubound

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

基于ahuth的回答 ;

 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

testing空数组的另一个解决scheme

 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个string数组,所以他们不共享相同的string。

 ' 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 ' 
 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