在VBA中真的不可能声明0长度的数组吗?如果我尝试这样做:
Dim lStringArr(-1) As String
我收到一个编译错误,说range没有值。如果我试图欺骗编译器并在运行时像这样重做:
ReDim lStringArr(-1)
我收到下标超出范围的错误。
我略微改变了上面的内容,但是没有运气。
Dim lStringArr(0 To -1) As String
我想将变量数组转换为字符串数组。变体数组可能是空的,因为它来自字典的Keys属性。 keys属性会返回一组变体。我想要在代码中使用字符串数组,因为我有一些函数可以处理要使用的字符串数组。这是我正在使用的转换函数。由于lMaxIndex = -1,这将导致下标超出范围错误:
Public Function mVariantArrayToStringArray(pVariants() As Variant) As String()
Dim lStringArr() As String
Dim lMaxIndex As Long, lMinIndex As Long
lMaxIndex = UBound(pVariants)
lMinIndex = LBound(pVariants)
ReDim lStringArr(lMaxIndex)
Dim lVal As Variant
Dim lIndex As Long
For lIndex = lMinIndex To lMaxIndex
lStringArr(lIndex) = pVariants(lIndex)
Next
mVariantArrayToStringArray = lStringArr
End Function
返回包含一个空字符串的单例数组。注意-这不是我们想要的。我们想要一个空数组-这样遍历它就像什么都不做。但是包含空字符串的单例数组通常可以工作,例如如果我们以后想将所有字符串都连接到字符串数组中。
Public Function mVariantArrayToStringArray(pVariants() As Variant) As String()
Dim lStringArr() As String
Dim lMaxIndex As Long, lMinIndex As Long
lMaxIndex = UBound(pVariants)
lMinIndex = LBound(pVariants)
If lMaxIndex < 0 Then
ReDim lStringArr(1)
lStringArr(1) = ""
Else
ReDim lStringArr(lMaxIndex)
End If
Dim lVal As Variant
Dim lIndex As Long
For lIndex = lMinIndex To lMaxIndex
lStringArr(lIndex) = pVariants(lIndex)
Next
mVariantArrayToStringArray = lStringArr
End Function
这是我用来将变量数组转换为字符串数组的函数。 Comintern的解决方案似乎更高级,更通用,如果我仍然坚持使用VBA进行编码,我可能会切换到这一天:
Public Function mVariantArrayToStringArray(pVariants() As Variant) As String()
Dim lStringArr() As String
Dim lMaxIndex As Long, lMinIndex As Long
lMaxIndex = UBound(pVariants)
lMinIndex = LBound(pVariants)
If lMaxIndex < 0 Then
mVariantArrayToStringArray = Split(vbNullString)
Else
ReDim lStringArr(lMaxIndex)
End If
Dim lVal As Variant
Dim lIndex As Long
For lIndex = lMinIndex To lMaxIndex
lStringArr(lIndex) = pVariants(lIndex)
Next
mVariantArrayToStringArray = lStringArr
End Function
答案 0 :(得分:5)
如评论中所述,您可以通过在Split
上以documented here的形式调用vbNullString
来“本地”执行此操作:
表达式-必需。包含子字符串和定界符的字符串表达式。如果expression是零长度的字符串(“”),则Split返回一个空数组,即没有元素和数据的数组。
如果您需要更通用的解决方案(即其他数据类型),则可以直接在oleaut32.dll中调用SafeArrayRedim
函数,并要求它将传递的数组重新定义为0个元素。您必须跳过几圈以获得数组的基地址(这是由于VarPtr
函数的怪异所致)。
在模块声明部分:
'Headers
Private Type SafeBound
cElements As Long
lLbound As Long
End Type
Private Const VT_BY_REF = &H4000&
Private Const PVDATA_OFFSET = 8
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias _
"RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, _
ByVal length As Long)
Private Declare Sub SafeArrayRedim Lib "oleaut32" (ByVal psa As LongPtr, _
ByRef rgsabound As SafeBound)
过程-向其传递一个初始化的数组(任何类型),它将删除其中的所有元素:
Private Sub EmptyArray(ByRef vbArray As Variant)
Dim vtype As Integer
CopyMemory vtype, vbArray, LenB(vtype)
Dim lp As LongPtr
CopyMemory lp, ByVal VarPtr(vbArray) + PVDATA_OFFSET, LenB(lp)
If Not (vtype And VT_BY_REF) Then
CopyMemory lp, ByVal lp, LenB(lp)
Dim bound As SafeBound
SafeArrayRedim lp, bound
End If
End Sub
样品用量:
Private Sub Testing()
Dim test() As Long
ReDim test(0)
EmptyArray test
Debug.Print LBound(test) '0
Debug.Print UBound(test) '-1
End Sub
答案 1 :(得分:1)
制作一个专用的实用程序函数,该函数返回VBA.Strings.Split
函数的结果,以vbNullString
处理,该函数实际上是一个空字符串指针,与使用空字符串文字{ {1}},它也可以工作:
""
现在分支您的函数以检查键是否存在,如果没有键,则返回Public Function EmptyStringArray() As String()
EmptyStringArray = VBA.Strings.Split(vbNullString)
End Function
,否则继续调整结果数组的大小并转换每个源元素。