【问题标题】:How to convert a comma delimited string to a two dimensional array如何将逗号分隔的字符串转换为二维数组
【发布时间】:2019-04-19 12:53:17
【问题描述】:

我有一个csv 文件,该文件用Lf 终止符分隔,我想将其转换为二维数组以进行进一步处理。我成功地将文件读入字符串并将行终止符从Lf 修改为Cr,因为我了解vba 不将Lf 识别为终止符。我想获取这个字符串并创建一个二维数组,我还可以在其中确定行数和列数,因为原始 csv 文件可以是任意大小。 csv 文件也可以很大(>300 MB 和 >1M 元素)

即使每个数据行的字符串中有一个CR 终止符,我也无法弄清楚如何确定列数。下面的代码显示了我如何创建以Cr 作为终止符的逗号分隔字符串

Open fName For Binary As #1

     Buf$ = String$(LOF(1), 0)
     Get 1, , Buf$
     Buf$ = Replace$(Buf$, vbLf, vbCr) ' Replace LF with CR

Close #1

我想要一个方法或函数来创建一个二维数组并计算行数和列数

【问题讨论】:

  • 我真的不知道你会得到什么样的执行速度,但是有 String.Split 函数。我认为您可以在 CR 上拆分字符串以生成一个数组,然后遍历该数组并用逗号拆分每个元素,从而构建您的多维数组。
  • 如果您的字段值可能包含逗号,那么您将有更多工作要做。您是否尝试过直接在 Excel 中打开文件?这将是最直接的方法。
  • 我可以尝试 String.Split 函数并测量我也关心的性能,因此最初并没有走这条路。我试图避免在单元格中读取或写入任何值,因为我知道这非常慢,而且我正在处理接近一百万个元素的大型数组。
  • @XGeek 您是否尝试过使用非标准符号(例如 µ)替换并使用该符号作为分隔符的 texttocolumns? .TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, Other:=True, OtherChar:="µ" 使用该符号

标签: excel vba


【解决方案1】:

首先想到的是使用InStr(),它显示字符串中字符的位置。预先定义数组维度(数据集的最后一行);在简短的示例中,我将使用i 作为循环的迭代器)

sep = InStr(Cells(i,1).Value,"BS") 'swap BS for whatever you want to separate on

然后使用单独的(sep)到任一数组

arr(i,1) = left(Cells(i,1).value,sep-1)
arr(i,2) = right(Cells(i,1).value,len(cells(i,1))-sep+2) '2 characters in sep "b" and "s" so adding that back

我建议对您的代码进行的更改是使用一些符号或字符串而不是回车符,以便轻松分隔。

【讨论】:

  • 我正在尝试解析一个字符串变量,该变量是从一个用逗号分隔并以 Cr 作为行终止符的大型 csv 文件创建的。如果有帮助,我可以创建一个不同的行终止符。该文件旨在创建一个最终包含大约 300 列和 100 数千行的数组。我不确定如何使用 InStr,因为有很多逗号分隔符,而且我不知道所需数组的大小,因为它将是可变的
  • @XGeek 您可以动态确定列/行(请参阅this)。有了它,您可以使用动态变量创建一个数组(存储在 VBA 中,以便更快地迭代)。
【解决方案2】:

我会尝试这样做:

  1. 首先使用 vbNewLine 将数据拆分成行。
  2. 然后循环拆分数组,并使用逗号分隔符拆分每次迭代。留下一个锯齿状数组(包含数组的数组)。
  3. 最后,您现在有了两个 dim 数组 ReDim 的维度,并在其上循环以添加所有数据。

出于抽象目的,我将这个任务分成三个独立的函数。


要调用的主函数

我将分隔符设为可选,因此它不仅限于逗号。

这不考虑转义字符,如果需要,您必须添加。

Private Function TextFileToArray(ByVal FilePath As String, Optional ByVal Delimiter As String = ",") As Variant

    'READ THE CONTENTS FROM TEXTFILE
    Dim FileContent As String
    FileContent = ReadTextFile(FilePath)

    'SEPERATE THE ROWS USING vbNewLine
    Dim SplitData As Variant
    SplitData = Split(FileContent, vbNewLine)

    'CREATE A JAGGED ARRAY BY SPLITTING EACH STRING
    Dim JaggedArray As Variant
    ReDim JaggedArray(LBound(SplitData, 1) To UBound(SplitData, 1))

    Dim Index As Long
    For Index = LBound(SplitData, 1) To UBound(SplitData, 1)
        JaggedArray(Index) = Split(SplitData(Index), Delimiter)
    Next Index

    'CONVERT JAGGED ARRAY INTO A TWO DIM ARRAY
    TextFileToArray = JaggedArrayToTwoDimArray(JaggedArray)

End Function

读取文本文件的内容

这可以写在 main 函数中,但通常最好尝试将代码分成更小的块。

Public Function ReadTextFile(ByVal FilePath As String) As String

    Dim Fso As Object
    Set Fso = CreateObject("Scripting.FileSystemObject")

    Dim Ts As Object
    Set Ts = Fso.OpenTextFile(FilePath, 1, False)

    ReadTextFile = Ts.ReadAll

End Function

将锯齿状数组转换为二维数组

我已将边界存储在变量中,以便于调试和阅读。

Private Function JaggedArrayToTwoDimArray(ByVal SourceArray As Variant) As Variant

    'CAPTURE BOUNDS
    Dim LB1 As Long
    LB1 = LBound(SourceArray, 1)

    Dim UB1 As Long
    UB1 = UBound(SourceArray, 1)

    Dim LB2 As Long
    LB2 = LBound(SourceArray(LB1), 1)

    Dim UB2
    UB2 = UBound(SourceArray(UB1), 1)

    'SET BOUNDS OF RETURN ARRAY
    Dim ReturnArray As Variant
    ReDim ReturnArray(LB1 To UB1, LB2 To UB2)

    'POPULATE TWO DIM ARRAY FROM JAGGED ARRAY
    Dim RowIndex As Long
    For RowIndex = LB1 To UB1

        Dim ColIndex As Long
        For ColIndex = LB2 To UB2
            ReturnArray(RowIndex, ColIndex) = SourceArray(RowIndex)(ColIndex)
        Next ColIndex

    Next RowIndex

    JaggedArrayToTwoDimArray = ReturnArray

End Function

请随意添加错误处理和任何可能需要的更改。

【讨论】:

  • 将使用 vbNewLine 作为分隔符的 Split 函数仅与 LF 终止符一起使用还是需要 CR?我对锯齿状数组不是很熟悉,那么为什么它们在这种情况下会有所帮助?
  • VbNewLine 是一个常量,应该与 LF 或 CR 一起使用,因此您不必更改它。锯齿状数组只是一个包含数组的数组;示例:数组(数组(0, 1),数组(0, 2),数组(0, 3))。好处是我们可以将每一行文本拆分成自己的数组,用逗号分隔。
  • 您提出的代码主要使用 2 个例外:Split 函数失败,因为 vbNewLine 被忽略,导致所有数据都映射到第一个数组元素。我将分隔符切换为 vbLf,它是文件中的终止符,然后它起作用了,将每个数据行映射到一个唯一的数组元素。二维数组的创建也失败了,但那是因为我的 csv 源文件的最后一行有一个空白,导致 UB2 变为负数,这是一个简单的修复。考虑到这一点,我可以只访问 JaggedArray 中的数据而避免创建 2D 数组吗?
  • 有趣的是,VbNewLine 不起作用,但我很高兴你让它起作用。我找到了this 堆栈溢出答案,它显示了换行符的情况。只是好奇,你用的是什么操作系统?是的,如果这对你有用,你可以简单地访问这个例子中的锯齿状数组。
  • 我使用的是 Windows,但 csv 文件来自一个只有 LF 终止符的 Android 应用程序。我相信 VbNewLine 对我不起作用,因为它相当于 Chr(13) + Chr(10)。您的锯齿状数组代码效果很好,但我在性能方面遇到了困难,所以我最终只使用了一个使用 Split 函数创建的字符串数组,并在我需要的逗号分隔字符串中选择数据,而不是尝试预先创建一个数组以避免漫长的等待时间。您让我走上了正确的道路,非常感谢您!
猜你喜欢
  • 1970-01-01
  • 2020-05-14
  • 2019-05-15
  • 2020-05-21
  • 2011-06-18
  • 2019-05-19
  • 1970-01-01
相关资源
最近更新 更多