使用公式/ VBA将长度分隔的CSV文件解析为140列

时间:2014-12-15 19:56:50

标签: excel vba excel-vba excel-formula excel-2010

在我的工作中,我必须每周清理原始数据文件,使其与特定表格相匹配。

数据以CSV文件形式存在,因此一条记录的所有数据都在一行上。 CSV的样子:

  • 每条记录(行)必须拆分为140列。

  • 一个CSV中可以有超过20,000行。

  • 文件不是用符号分隔的,而是每列都是一个 特定的字符数与行数据字符串的对应 特定长度。

  • 列的指定空间不是常量。姓氏列是 比产品代码列长。

  • 我们还需要在更改后更改某些列的格式 输入。这就是为什么在代码部分我对数据(1)有“00”+。一世 如果我得到代码工作,计划稍后添加更多 相当快。

到目前为止使用的是一种简单的方法,我们将CSV文件内容转储到Sheet1的第一列,然后Sheet2中的公式使用mid()函数来解析20,000多行数据并将其拆分为列。 (例如:= MID(Sheet1!$ A1,B $ 1,B $ 2),其中B $ 1和B $ 2包含此列的具体位置和长度)

但是,由于Sheet2实际上完全充满了mid()公式,因此文件大小超过50 MB。这使得Workbook工作缓慢,并且已知它会因大文件而崩溃。

对我来说,解析行的更好方法是使用VBA。但是,我试图创建一个数组循环,它将解析一行,将值放到Sheet2然后循环直到所有行都完成。该代码可以工作,但是当我用23,943行数据进行测试时,它将我的计算机锁定了11分钟。

所以问题是:我是否坚持使用公式,我的代码是否有问题或是否有解决这个问题的工作方式?

这是我的代码:

Option Explicit
Sub Attempt2()

Dim Data(1 To 140) As Variant
Dim shSource As Range
Dim i As Integer
Dim location As Integer
Dim Rows As Integer
Dim LastRow As Integer


LastRow = Worksheets("Sheet1").Range("A65536").End(xlUp).Row

For Rows = 1 To LastRow

'Set the source cell that is being parsed

Set shSource = Worksheets("Sheet1").Cells(Rows, 1)

'Array picks up all 140 values

Data(1) = "00" + Mid(shSource, 1, 2)
Data(2) = Mid(shSource, 3, 9)
Data(3) = Mid(shSource, 12, 16)
Data(4) = Mid(shSource, 28, 12)
Data(5) = Mid(shSource, 40, 1)
Data(6) = Mid(shSource, 41, 35)
Data(7) = Mid(shSource, 76, 19)
Data(8) = Mid(shSource, 95, 2)
Data(9) = Mid(shSource, 97, 5)
Data(10) = Mid(shSource, 102, 4)
Data(11) = Mid(shSource, 106, 8)
Data(12) = Mid(shSource, 114, 5)
Data(13) = Mid(shSource, 120, 5)
Data(14) = Mid(shSource, 125, 5)

location = 130


For i = 15 To 113

    Data(i) = Mid(shSource, location, 6)
    location = location + 6

Next i

Data(114) = Mid(shSource, 724, 3)
location = location + 3

For i = 115 To 118
    Data(i) = Mid(shSource, location, 6)
    location = location + 6

Next i

Data(119) = Mid(shSource, 751, 3)
location = location + 3

For i = 120 To 123
    Data(i) = Mid(shSource, location, 6)
    location = location + 6

Next i

Data(124) = Mid(shSource, 778, 3)
location = location + 3

For i = 125 To 140
    Data(i) = Mid(shSource, location, 6)
    location = location + 6
Next i

'Print one row

For i = 1 To 140
    Worksheets("Sheet2").Cells(Rows + 1, i).Value = Data(i)
Next i

Next Rows


End Sub

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

您可以通过关闭ScreenUpdating并将Application.Calculation设置为手动来加速您的代码(完成后不要忘记重置为自动!)

另外

(1)您为每个循环读取输入单元格值140次:更快地将值读入变量,然后对该变量运行Mid()次调用

Dim v As String
v = Worksheets("Sheet1").Cells(Rows, 1).Value
Data(1) = "00" + Mid(v, 1, 2)
'etc

(2)将数组分配给工作表时,您可以在一行中执行此操作:

Worksheets("Sheet2").Cells(Rows + 1, 1).Resize(1, 140).Value = Data 

(无需循环)

更高级的方法是使用数组在内存中进行各种操作,但我首先尝试上面的步骤,看看你得到了什么样的改进。