如何检查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
)。 更重要的是, FileExists
比Dir
更清楚地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