我正在尝试学习如何在VBA中使用stringbuilder函数,但是在VBA中查找有关如何使用它们的资源时遇到了问题。我可以使用一些帮助来使用预制的stringbuilder类。
我知道这些潜艇中的每一个都在编写最终代码方面发挥了一定作用。例如,我看过其他使用"string.append"
的示例,但我不确定在这种情况下它是否有效。我可以使用一些洞察力来了解如何使用此代码。请帮忙!
让我理解的最好方法是,如果有人可以使用这个示例stringbuilder类将几行示例代码放在一起。谢谢!!
Private m_arrBuffer
Private m_strDelimiter
Private Sub Class_Initialize()
m_arrBuffer = Array()
m_strDelimiter = “”
End Sub
Private Sub Class_Terminate()
m_arrBuffer = Empty
End Sub
Public Property Get Delimiter()
Delimiter = m_strDelimiter
End Property
Public Property Let Delimiter(strDelimiter)
m_strDelimiter = strDelimiter
End Property
Public Sub Append(strValue)
ReDim Preserve m_arrBuffer(UBound(m_arrBuffer) + 1)
m_arrBuffer(UBound(m_arrBuffer)) = strValue
End Sub
Public Sub AppendLine(strValue)
Me.Append strValue & vbCrLf
End Sub
Public Sub Compact()
If Not Me.Delimiter = “” Then
strOriginalDelimiter = Me.Delimiter
Me.Delimiter = “”
End If
strTemp = Me.ToString
m_arrBuffer = Array()
Me.Append strTemp
Me.Delimiter = strOriginalDelimiter
End Sub
Public Function ToArray()
ToArray = m_arrBuffer
End Function
Public Function ToString()
ToString = Join(m_arrBuffer, m_strDelimiter)
End Function
答案 0 :(得分:5)
VBA中的字符串连接(&
)非常慢,所以经常" stringbuilder"像这样的类用于加速过程,如果你需要组合大量的字符串。
一般的想法是使用Array()
存储单个字符串组件,然后在需要时使用Join()
函数将所有字符串组合。在添加字符串时自动调整数组大小。许多人使用"GrowBy"
功能(尽管没有这个功能)在达到阵列限制时通过静态大小或因子来增长数组。这也可以提高性能,因为为每个字符串插入调用ReDim Preserve
可能会造成损失。
要回答您的问题,请假装您需要构建HTML文件的一部分。您可以像这样使用显示的字符串类:
Dim sb
Set sb = New StringBuilder ' Guessing here. You haven't shown the class name.
sb.Append "some string"
sb.Append "another string"
sb.Append "a third string"
....
sb.Delimiter = "<br>"
myHtmlFile.Write sb.ToString()
将打印以下内容:
some string<br>another string<br>a third string
这是一般的想法。通过使用数组尽可能避免使用&
,您应该会看到一些显着的性能改进。
答案 1 :(得分:1)
我不确定我是否遵循了你的问题,因为VBA没有字符串构建器。字符串可以简单地构建。
Dim strTemp as string
Dim strCountry as string
strCountry = "Nowhere"
strTemp = "I am from " & strCountry
答案 2 :(得分:1)
我同意@MatthewD,但如果您在练习中这样做,我会添加更多信息。
以下是来自Chip Pearson伟大网站的declaring variables和using classes in VBA的一些链接。
您需要向VBA项目添加新的类模块并粘贴代码。小心 - 你的例子中的语音标记可能需要被替换,它们在某处被破坏成类似但看起来不同的字符。将类模块的名称更改为“StringBuilder”然后你可以使用像这样的普通模块:
Sub test1()
Dim strBld As StringBuillder
Set strBld = New StringBuillder
strBld.Append "Hello"
strBld.Append " world"
strBld.Append "!"
Debug.Print strBld.ToArray(0)
Debug.Print strBld.ToString
End Sub
答案 3 :(得分:0)
这是一个古老的问题,OP可能已经进行了。但是,当我寻找有关此问题的信息时,这就是我找到的页面。如果其他人找到了,这是我的尝试,它是一个更好的答案,并链接到一个甚至更好的答案。
在问题或之前的任何答案中,我都找不到对问题的充分解释。在我的实验中,可接受的答案比内置的构建长字符串的方法要差。
问题
假设我写:
StrVar = "abcde"
StrVar = StrVar & "fghij"
StrVar = StrVar & "klmno"
对于第一条语句,VBA解释器找到足以容纳5个字符的内存,将“ abcde”写入该内存,并将StrVar指向该内存。
对于第二条语句,VBA解释器找到足以容纳10个字符的内存,将StrVar的现有内容复制到该内存中,附加“ fghij”,将StrVar指向该内存,然后释放旧内存以进行垃圾回收。
对于第三条语句,VBA解释器找到足以容纳15个字符的内存,将StrVar的现有内容复制到该内存,附加“ klmno”,将StrVar指向该内存,并释放旧内存以进行垃圾回收。
重点是VBA字符串是不可变;他们永远不会改变。而是,每次您的宏修改字符串时,都会为修改后的字符串找到新的内存,并释放原始字符串的内存。对于一些字符串修改,关于已释放的内存没有任何处理,因此没有明显的时间浪费在构建长字符串上。但是,如果您经常执行此操作,则解释器将耗尽新的内存,并且必须调用垃圾回收器。垃圾收集器遍历所有内存,以识别哪些位仍在使用中,哪些位未被使用。它将所有仍在使用的位移动在一起,将未使用的位保留为新的可用内存。控制权返回给解释器,解释器继续处理新的字符串分配,直到再次用尽新的内存为止。
如果您构建的字符串越来越长,解释器将越来越快地用完内存,直到您的宏慢到抓取为止。
我想实现的目标,解决方案和更快的解决方案
我想将Excel范围转换为HTML。忽略格式,我想创建一个像这样的字符串:
<table>
<tr>
<td> … </td>
<td> … </td>
</tr>
<tr>
<td> … </td>
<td> … </td>
</tr>
<tr>
<td> … </td>
<td> … </td>
</tr>
</table>
在我的笔记本电脑上,宏构建此字符串的持续时间一直稳定增长,直到大约10,000个单元。然后它开始显着减速:
Duration
in secs Cells
0.000 200
0.016 400
0.031 1,000
0.062 2,000
0.14 4,000
0.44 8,000
0.67 10,000
0.97 12,000
2.27 14,000
6.79 16,000
10.9 18,000
63 32,000
在我的笔记本电脑上,8,000个细胞耗时是4,000个细胞的3倍; 16,000个单元的时间是8,000个单元的15倍,而32,000个单元的时间则是16,000个单元的9倍。如果重复我的实验,计算机持续时间的增加将取决于您拥有多少内存以及您在做什么。
我不希望需要转换32,000个单元格。但是,对于此实验,我仅转换了单元格值。一旦我开始转换格式,字符串长度将急剧增加,并且性能可接受的最大单元数将减少,
我的下一个想法是创建一个字符串数组,每行一个元素。将每个表行输出到字符串数组的不同元素,然后Join
将元素输出以创建完整字符串。这与接受的答案中的想法相同。当我尝试此想法时,32,000个单元花费了91秒。也许我可以通过优化代码来减少持续时间,但这似乎不是一个有前途的方法。
我的下一个想法是将字符串的每一位写入光盘文件,然后读取文件以获取全部内容。我没有给它们适当的时间,但是光盘的读写似乎总是足够快。通过这种方法,持续时间为:
Duration
in secs Cells
.375 10,000
.609 18,000
3.45 100,000
34.8 1,000,000
这些持续时间更可接受。当我开始转换格式时,持续时间会增加,但是由于1,000,000个单元格比我预期的要多得多,因此我应该可以获得可接受的性能。
为了展示我的技术,这是我代码的重要部分:
' Needs reference to Microsoft Scripting RunTime
Dim Body As String
Dim ColCrnt As Long, ColLeft As Long, ColRight As Long
Dim FileOut As TextStream
Dim Fso As FileSystemObject
Dim PathFileName As String
Dim RowBot As Long, RowCrnt As Long, RowTop As Long
Dim Wsht As Excel.Worksheet
Set Fso = CreateObject("Scripting.FileSystemObject")
PathFileName = ThisWorkbook.Path & "\RtH.txt"
' Create text file. First True = Overwrite existing file. Second True = Unicode output
Set FileOut = Fso.CreateTextFile(PathFileName, True, True)
FileOut.WriteLine "<table>"
For RowCrnt = RowTop To RowBot
FileOut.WriteLine " <tr>"
For ColCrnt = ColLeft To ColRight
FileOut.WriteLine " <td>" & Wsht.Cells(RowCrnt, ColCrnt).Value & "</td>"
Next
FileOut.WriteLine " </tr>"
Next
FileOut.WriteLine "</table>"
FileOut.Close
' Open text file. 1 = Open for reading. -1 = Unicode
Set FileOut = Fso.OpenTextFile(PathFileName, 1, -1)
Body = FileOut.ReadAll
FileOut.Close
在这个答案中已经走得很远了,我又寻找了一个解决字符串构建问题的方法,并发现:A lightning-fast StringBuilder
此页面包含该解决方案的多个版本,因为不同的人建议进行改进。我尝试过杜兰(Duran)的版本。我用于转换1,000,000个单元的代码的持续时间从使用光盘解决方案的34.8秒减少到了3.92秒。
我的解决方案的优势在于它仅使用简单易用的VBA,并且比其他任何简单解决方案都快。我已经对它在16位Unicode范围内的各种字符进行了测试,没有问题。
链接的解决方案使用了更高级的VBA。我不会阻止您使用它;您在不知道VBA标准例程如何工作的情况下使用它们。我建议阅读解决方案的每个版本和每个注释,因为这里有很多有用的信息。我选择了Duran版本,但您可能希望使用其他版本。我在任何答案或评论中都找不到的唯一重要一点是,代码必须必须放在名为“ StringBuilder”的类模块中。