Я хочу проверить пустые массивы. 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
пусто. Любой способ избежать этого?
Как вы имеете дело со строковым массивом, считаете ли вы Join?
If Len(Join(FileNamesList)) > 0 Then
Go с тройным отрицательным:
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
для XOR с -1, возвращая тем самым нуль, если хотите.
(Not myArray) (Not Not myArray)
Uninitialized -1 0
Initialized -someBigNumber someOtherBigNumber
Function isArrayInitialized2(Arr As Variant) As Boolean
If (Not Arr) = -1 Then isArrayInitialized2 = False Else isArrayInitialized2 = True
End Function
If (Not Arr) = -1 Then isArrayInitialized2 = False Else isArrayInitialized2 = True
End Function
Если вы проверите функцию массива, она будет работать для всех границ:
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)=-1
и LBound(arr)=0
. Эта проблема рассматривается в IsArrayEmpty Чипа Пирсона. Вот почему я связался с этим в своем комментарии к вопросу.
Я вижу похожие ответы здесь... но не мои...
Вот как я, к сожалению, собираюсь разобраться с этим... Мне нравится подход 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
Я просто вставляю под кодом великого Чипа Пирсона. Это работает. Здесь его страница о функциях массива.
Надеюсь, это поможет.
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
При написании 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
Этот код не выполняет то, что вы ожидаете:
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
, если он этого не делает). Что еще, FileExists
выражает намерение вашего кода намного ясно, чем Dir
.
Способ 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
Упрощенная проверка для пустого массива:
Dim exampleArray() As Variant 'Any Type
If ((Not Not exampleArray) = 0) Then
'Array is Empty
Else
'Array is Not Empty
End If
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
Основываясь на 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
Чтобы проверить, является ли массив байтов пустым, самым простым способом является использование функции VBA StrPtr()
.
Если массив байтов пуст, StrPtr()
возвращает 0
; в противном случае он возвращает ненулевое значение (однако он не адрес для первого элемента).
Dim ar() As Byte
Debug.Assert StrPtr(ar) = 0
ReDim ar(0 to 3) As Byte
Debug.Assert StrPtr(ar) <> 0
Однако он работает только с массивом Byte.
Вот еще один способ сделать это. Я использовал его в некоторых случаях, и он работает.
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
Другим методом было бы сделать это раньше. Вы можете создать логическую переменную и установить ее в true после загрузки данных в массив. поэтому все, что вам действительно нужно, это простой оператор 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
UBound > LBound
. В VBA у вас может быть запущен индекс массива, например, от -5321 To -4112
. Просто одна из "забавных" причуд языка.
if Ubound(yourArray)>-1 then
debug.print "The array is not empty"
else
debug.print "EMPTY"
end if
Function IsVarArrayEmpty(anArray As Variant) as boolean
On Error Resume Next
IsVarArrayEmpty = true
IsVarArrayEmpty = UBound(anArray) < LBound(anArray)
End Function
== > возможно, ubound сбой, и он остается верным, и если ubound
Вы можете проверить, нет ли массива пустым, путем подсчета общего количества элементов с использованием объекта 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 мксека для каждого элемента + инициализация 15 мс, поэтому массив из элементов 10М занимает около 3 секунд. Та же функциональность может быть реализована через ScriptControl
ActiveX (она недоступна в 64-разрядных версиях MS Office, поэтому вы можете использовать обходной путь, например this).
Вы можете использовать следующую функцию, чтобы проверить, нет ли пустого или строкового массива в 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
Лично я считаю, что один из приведенных выше ответов может быть изменен, чтобы проверить, имеет ли массив содержимое:
if UBound(ar) > LBound(ar) Then
Это относится к отрицательным номерам ссылок и занимает меньше времени, чем некоторые другие параметры.
ReDim
ed), а также для массивов, которые имеют только один элемент. Также это в значительной степени плагиат от других (неправильных) ответов на этот вопрос?
Другое решение для проверки пустого массива
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
'
Я обобщу проблему и вопрос, как предполагалось. Тестирование в массиве и улавливание возможной ошибки
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... это вероятно? в weirdland, да.
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)
.
IsArrayEmpty
делает то, что вы хотите.