将工作表转换为仅包含字符串的数组

时间:2012-10-12 14:20:28

标签: excel excel-vba vbscript vba

我需要将excel工作表中的数据提取到将在使用VBScript作为脚本语言(Quick Test Professional)的应用程序中使用的数组。我们可以使用以下代码:

' ws must be an object of type Worksheet
Public Function GetArrayFromWorksheet(byref ws)
    GetArrayFromWorksheet = ws.UsedRange.Value
End Function

myArray = GetArrayFromWorksheet(myWorksheet)
MsgBox "The value of cell C2 = " & myArray(2, 3)

一切都很好,但不幸的是,返回的数组不仅包含文字文本字符串,还包含date,integer,double等类型的原语。它发生了多次,数据被转换。

[edit] 示例:在单元格中输入=NOW()并将单元格格式设置为hh:mm时,显示的值 17:45 ,上述方法返回类型为double的变量和类似 41194.7400990741

的值

以下解决方案效果更好:我可以使用.Text属性从单元格中获取文字文本,但它们只能在一个单元格上工作,而不能在一系列单元格上工作。我不能像.Value属性那样立即对数组执行此操作,因此我必须一次填充数组一个单元格:

Public Function GetArrayFromWorksheet_2(byref ws)
    Dim range, myArr(), row, col
    Set range = ws.UsedRange

    ' build a new array with the row / column count as upperbound
    ReDim myArr(range.rows.count, range.columns.count)

    For row = 1 to range.rows.count
        For col = 1 to range.columns.count
            myArr(row, col) = range.cells(row, col).text
        Next
    Next

    GetArrayFromWorksheet_2 = myArr
End Function

但是哎呀......一个嵌套的for loop。是的,在大型工作表上有明显的性能下降 有人知道更好的方法吗?

3 个答案:

答案 0 :(得分:2)

正如我们在评论中所述,为了避免这个问题,您需要在某个时刻遍历数组。但是,我发布此信息是因为 可能 会根据工作表中的数据类型显着提高速度。由于200个单元格是数字的一半,因此速度提高约38%。使用相同比例的600个细胞,改善率为41%。

通过循环遍历数组本身,并且只检索解释为双精度(数字)的值的.Text,如果存在大量非双精度数据,则可以看到速度提高。这不会检查.Text是否包含带文本的单元格,日期格式为日期或空白单元格。

Public Function GetArrayFromWorksheet_3(ByRef ws)

    Dim range, myArr, row, col
    Set range = ws.UsedRange

    'Copy the values of the range to temporary array
    myArr = range
    'Confirm that an array was returned.
    'Value will not be an array if the used range is only 1 cells
    If IsArray(myArr) Then
        For row = 1 To range.Rows.Count
            For col = 1 To range.Columns.Count
                'Make sure array value is not empty and is numeric
                If Not IsEmpty(myArr(row, col)) And _
                            IsNumeric(myArr(row, col)) Then
                    'Replace numeric value with a string of the text.
                    myArr(row, col) = range.Cells(row, col).Text
                End If
            Next
        Next
    Else
        'Change myArr into an array so you still return an array.
        Dim tempArr(1 To 1, 1 To 1)
        tempArr(1, 1) = myArr
        myArr = tempArr
    End If

    GetArrayFromWorksheet_3 = myArr
End Function

答案 1 :(得分:0)

  • 将工作表复制到新工作表中。
  • 复制粘贴值以删除公式
  • 为每列的列添加文本,将每列转换为文本
  • 按照您最初的操作加载阵列
  • 删除新工作表

答案 2 :(得分:0)

如果不循环使用工作表,您无法快速轻松地完成此操作。 如果您使用上面的技术使用2行代码,那么它必须是变体类型数组。

我已经在我的代码中包含了一个真实的例子,它在6行中完成,因为我喜欢A)使用工作表对象和B)保持变量方便原始的最后一行。

Dim wsKeyword As Worksheet
Set wsKeyword = Sheets("Keywords")

Dim iLastKeywordRow As Long
iLastKeywordRow = wsKeyword.Range("A" & wsKeyword.Rows.Count).End(xlUp).Row

Dim strKeywordsArray As Variant
strKeywordsArray = wsKeyword.Range("A1:N" & iLastKeywordRow).Value

请注意,您的数组必须是一种可以这种方式使用的变体。

Variants这样工作的原因是,当您创建变体数组时,数组中的每个“单元格”都设置为变体类型。然后每个单元格获得它的变体类型设置为分配给它的任何类型的值。因此,为字符串分配的变量将设置为variant.string,现在只能用作字符串。在您的原始示例中,您看起来有时间值,它们存储为variant.time而不是variant.string。

有两种方法可以解决原始问题 1)循环并使用更多控件执行该过程,如双嵌套for循环。在另一个答案中解释,它给你完全控制 2)按原样存储数组中的所有数据,然后将其重新格式化为第二个数组,或者在使用时将其格式化为所需的文本(两者都应该更快)