Nice programing

vba 매크로에서 빈 배열을 확인하는 방법

nicepro 2020. 12. 13. 11:08
반응형

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비어 있기 때문에 . 그것을 피할 방법이 있습니까?


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에서는 어떤 이유로 든 Not myArraySafeArray 포인터를 반환합니다. 초기화되지 않은 배열의 경우 -1을 반환합니다. 당신은 할 수 있습니다 Not이 원하는 경우 따라서, 제로를 반환 -1을 XOR합니다.

               (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 접근 방식을 좋아하지만 배열이 빈 문자열의 배열이면 작동하지 않습니다 ...

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.FileSystemObjectover를 사용할 것입니다 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

나는 위대한 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

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

아래 함수를 사용하여 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

또 다른 방법은 더 빨리하는 것입니다. 부울 변수를 만들고 데이터를 배열에로드 한 후 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

Byte 배열이 비어 있는지 확인하려면 가장 간단한 방법은 VBA 함수를 사용하는 것 StrPtr()입니다.

바이트 배열이 비어있는 경우 StrPtr()반환 0; 그렇지 않으면 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) as boolean
    On Error Resume Next
    IsVarArrayEmpty = true
    IsVarArrayEmpty = UBound(anArray) < LBound(anArray)
End Function

아마도 ubound충돌하고 true로 유지되고 만약이면 ubound < lbound비어 있습니다.


의도 한대로 문제와 질문을 일반화하겠습니다. 어레이에 대한 평가 테스트 및 최종 오류 포착

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

이것은 음수 참조를 처리하고 다른 옵션 중 일부보다 시간이 덜 걸립니다.


You can check if the array is empty by retrieving total elements count using JScript's VBArray() object (works with arrays of variant type, single or multidimensional):

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

For me it takes about 0.3 mksec for each element + 15 msec initialization, so the array of 10M elements takes about 3 sec. The same functionality could be implemented via ScriptControl ActiveX (it is not available in 64-bit MS Office versions, so you can use workaround like this).


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

You can check its count.

Here cid is an array.

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

I hope this helps. Have a nice day!


Another solution to test for empty array

if UBound(ar) < LBound(ar) then msgbox "Your array is empty!"

Or, if you already know that LBound is 0

if -1 = UBound(ar) then msgbox "Your array is empty!"

This may be faster than join(). (And I didn't check with negative indexes)

Here is my sample to filter 2 string arrays so they do not share same strings.

' 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

참고URL : https://stackoverflow.com/questions/206324/how-to-check-for-empty-array-in-vba-macro

반응형