将 Excel 范围转换为 VBA 字符串 [英] Turn Excel range into VBA string

查看:40
本文介绍了将 Excel 范围转换为 VBA 字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将给定范围内的值转换为 VBA 字符串,其中原始单元格值由任何选定的列分隔符和行分隔符分隔.分隔符可以是一个字符或更长的字符串.行分隔符是行尾的字符串.字符串应该像我们从左上角、从左到右、到右下角读取文本一样完成.

以下是范围 A1:C5 中的 VALUES 示例:

+----+----+----+|A1 |B1 |C1 |+----+----+----+|A2 |B2 |C2 |+----+----+----+|A3 |B3 |C3 |+----+----+----+|A4 |B4 |C4 |+----+----+----+|A5 |B5 |C5 |+----+----+----+

所需的结果是一个 VBA 字符串:

A1,B1,C1@$A$2,$B$2,$C$2@A3,B3,C3@A4,B4,C4@A5,B5,C5@

为了便于阅读,我会这样显示:

A1,B1,C1@A2,B2,C2@A3,B3,C3@A4,B4,C4@A5,B5,C5@

作为列分隔符,我选择了 (逗号)和作为行分隔符的 @ 符号.当然,这些可以是任何字符,例如 \r\n.

我想要快速处理 range 中的字符串的原因是因为我想通过 ADO 连接将它发送到 SQL Server.到目前为止,我已经测试过它是即时传输大量数据的最快方法.如何在 SQL Server 上拆分此字符串的孪生问题在这里:

代码

函数 getRangeText(Source As Range, Optional rowDelimiter As String = "@", Optional ColumnDelimiter As String = ",")常数 CELLLENGTH = 255昏暗数据()将文本变暗为字符串Dim BufferSize As Double, length As Double, x As Long, y As LongBufferSize = CELLLENGTH * Source.Cells.Count文本 = 空间(缓冲区大小)数据 = 来源.价值对于 x = 1 到 UBound(Data, 1)如果 x >1 那么Mid(text, length + 1, Len(rowDelimiter)) = rowDelimiter长度 = 长度 + Len(rowDelimiter)万一对于 y = 1 到 UBound(Data, 2)如果长度 + Len(Data(x, y)) + 2 >Len(text) 然后 text = text &空间(CDbl(BufferSize/4))如果y>1 那么Mid(text, length + 1, Len(ColumnDelimiter)) = ColumnDelimiter长度 = 长度 + Len(ColumnDelimiter))万一Mid(text, length + 1, Len(Data(x, y))) = Data(x, y)长度 = 长度 + Len(Data(x, y))下一个下一个getRangeText = Left(text, length) &行分隔符结束函数

测试

Sub TestGetRangeText()Dim s 作为字符串昏暗的开始:开始 = 计时器s = getRangeText(ActiveSheet.UsedRange)Debug.Print "执行时间:";计时器 - 开始;秒"Debug.Print "行数:";ActiveSheet.UsedRange.Rows.Count;列: ";ActiveSheet.UsedRange.Columns.CountDebug.Print "结果长度:";格式(Len(s), "#,###")结束子

I would like to turn values in given range into VBA string where original cell values are separated by any chosen column delimiter and row delimiter. Delimiters could be one character or longer strings. The row delimiter is the string at the end of the line. The string should be done just as we read text from left top corner, from left to right, to bottom right corner.

Here is an example of the VALUES in range A1:C5:

+----+----+----+
| A1 | B1 | C1 |
+----+----+----+
| A2 | B2 | C2 |
+----+----+----+
| A3 | B3 | C3 |
+----+----+----+
| A4 | B4 | C4 |
+----+----+----+
| A5 | B5 | C5 |
+----+----+----+

Desired results is a VBA string:

A1,B1,C1@$A$2,$B$2,$C$2@A3,B3,C3@A4,B4,C4@A5,B5,C5@

For the sake of readability I will show it like this:

A1,B1,C1@
A2,B2,C2@
A3,B3,C3@
A4,B4,C4@
A5,B5,C5@

As a column delimiter I have chosen , (comma), and as a row delimiter @ sign. Of course these could be any characters like \r\n.

The reason why I want fast cooking of the string from range is because I want to to send it to SQL Server through ADO connection. As I have tested so far it is the fastest way to transfer lots of data on the fly. The twin question how to split this string on SQL Server is here: Split string into table given row delimiter and column delimiter in SQL server

Solution 1. Loop through all rows and columns. Question is if there be any more elegant way then just looping through all rows and columns? I would prefer VBA solution, not formula one.

Solution 2. Suggested by Mat's Mug in comment. CSV file is desired results. I would like to do it on the fly without saving. But good point - imitate CSV is what I want but I want it without saving.

Edit after bounty

Answer of Thomas Inzina works crazy fast and his solution is portable. Ordinary VBA loop turned out to be way faster then worksheet functions like JOIN on large data sets. I do not recommend using worksheet functions in VBA for that purpose. I have voted up everybody. Thank you all.

解决方案

To optimize performance my function emulates a String Builder.

Variables

  • Text: A very large string to hold the data
  • CELLLENGTH: A contant that determines the size of the BufferSize
  • BufferSize: The initial size of Text string
  • Data(): An Array derived from the source range

As the rows and columns of the Data() array are iterated over the current element (Data(x, y)) value replaces a portion of the Text string. The text string is resized as needed. This reduces the number of concatenations immensely. The initial BufferSize is set pretty high. I got my best results, 0.8632813 Second(s), by reducing CELLLENGTH to 25.

Download Sample Data from Sample-Videos.com

Results

Code

Function getRangeText(Source As Range, Optional rowDelimiter As String = "@", Optional ColumnDelimiter As String = ",")
    Const CELLLENGTH = 255
    Dim Data()
    Dim text As String
    Dim BufferSize As Double, length As Double, x As Long, y As Long
    BufferSize = CELLLENGTH * Source.Cells.Count
    text = Space(BufferSize)

    Data = Source.Value

    For x = 1 To UBound(Data, 1)
        If x > 1 Then
            Mid(text, length + 1, Len(rowDelimiter)) = rowDelimiter
            length = length + Len(rowDelimiter)
        End If

        For y = 1 To UBound(Data, 2)
            If length + Len(Data(x, y)) + 2 > Len(text) Then text = text & Space(CDbl(BufferSize / 4))
            If y > 1 Then
                Mid(text, length + 1, Len(ColumnDelimiter)) = ColumnDelimiter
                length = length + Len(ColumnDelimiter))
            End If

            Mid(text, length + 1, Len(Data(x, y))) = Data(x, y)
            length = length + Len(Data(x, y))
        Next
    Next

    getRangeText = Left(text, length) & rowDelimiter
End Function

Test

Sub TestGetRangeText()
    Dim s As String
    Dim Start: Start = Timer

    s = getRangeText(ActiveSheet.UsedRange)

    Debug.Print "Execution Time: "; Timer - Start; "Second(s)"
    Debug.Print "Rows: "; ActiveSheet.UsedRange.Rows.Count; "Columns: "; ActiveSheet.UsedRange.Columns.Count
    Debug.Print "Result Length: "; Format(Len(s), "#,###")
End Sub

这篇关于将 Excel 范围转换为 VBA 字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆