Как проверить пустой массив в макросе 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
пуст. Любой способ избежать этого?
- Сохраните каждый лист в книге для разделения файлов CSV
- Кнопка добавления / вычитания Excel VBA
- Где находится VBA Debug.Print?
- Количество строк по отфильтрованным данным
- Макрос для экспорта таблиц MS Word в листы Excel
- Запустить скрипт VBA из R
- Каков наиболее эффективный / быстрый способ циклического преобразования строк в VBA (excel)?
- Различие между использованием .text и .value в VBA Access
- Функция хеша пароля для Excel VBA
- Как восстановить случай по умолчанию переменной в VBA (Excel 2010)?
- Уникальные случайные числа с использованием VBA
- VBA: Различия в двух способах объявления нового объекта? (Попытка понять, почему мое решение работает)
- ExecuteExcel4Macro, чтобы получить значение из закрытой книги
Поскольку вы имеете дело со строковым массивом, считаете ли вы 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 по какой-либо причине Not myArray
возвращает указатель SafeArray. Для неинициализированных массивов возвращается -1. Вы не можете это сделать с XOR с -1, таким образом, возвращая ноль, если хотите.
(Not myArray) (Not Not myArray) Uninitialized -1 0 Initialized -someBigNumber someOtherBigNumber
Источник
Если вы проверите функцию массива, она будет работать для всех границ:
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
Этот код не делает то, что вы ожидаете:
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
Я просто вставляю ниже кода великий Чип Пирсон. Это работает.
Вот его страница о функциях массива .
Надеюсь, это поможет.
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
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
Упрощенная проверка для пустого массива:
Dim exampleArray() As Variant 'Any Type If ((Not Not exampleArray) = 0) Then 'Array is Empty Else 'Array is Not 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
Public Function IsEmptyArray(InputArray As Variant) As Boolean On Error GoTo ErrHandler: IsEmptyArray = Not (UBound(InputArray) >= 0) Exit Function ErrHandler: IsEmptyArray = True End Function
Другим методом было бы сделать это раньше. Вы можете создать логическую переменную и установить ее в true после загрузки данных в массив. поэтому все, что вам действительно нужно, это простая инструкция if, когда вы загружаете данные в массив.
Вот еще один способ сделать это. Я использовал его в некоторых случаях, и он работает.
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
Чтобы проверить, является ли массив байтов пустым, самым простым способом является использование функции 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 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
Это относится к отрицательным номерам ссылок и занимает меньше времени, чем некоторые другие параметры.
Вы можете использовать функцию ниже, чтобы проверить, пуст ли пул версий или строк в 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
Вы можете проверить, нет ли массива пустым, путем подсчета общего количества элементов с использованием объекта VBArray()
JScript (работает с массивами типа варианта, одно или многомерным):
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, поэтому вы можете использовать обходной путь, подобный этому ).
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 < lbound
, он пуст
Вы можете проверить его количество.
Здесь cid – массив.
if (jsonObject("result")("cid").Count) = 0 them MsgBox "Empty Array"
Надеюсь, это поможет. Хорошего дня!
Другое решение для проверки пустого массива
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 '
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