Vba 使用预先制作的Stringbuilder类

Vba 使用预先制作的Stringbuilder类,vba,excel,Vba,Excel,我试图学习如何在VBA中使用stringbuilder函数,但在VBA中查找有关如何使用它们的资源时遇到了困难。我可以使用一些帮助来使用预先制作的stringbuilder类 我确实知道,这些子类中的每一个都在编写最终代码中扮演着一定的角色。例如,我看到了使用“string.append”的其他示例,但我不确定它在本例中是否就是这样工作的。我可以对如何利用这段代码有一点了解。请帮忙 对于我来说,最好的理解方法是,如果有人可以使用这个示例stringbuilder类将几行示例代码组合在一起。谢谢

我试图学习如何在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

因为VBA没有字符串生成器,所以我不确定是否理解您的问题。可以简单地构建字符串

Dim strTemp as string
Dim strCountry as string

strCountry = "Nowhere"
strTemp = "I am from " & strCountry

我同意@MatthewD的观点,但如果你这样做是为了练习,我会补充更多信息

这里有一些来自Chip Pearson伟大网站的链接

您需要将新的类模块添加到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
<table>
  <tr>
    <td> … </td>
    <td> … </td>
  </tr>
  <tr>
    <td> … </td>
    <td> … </td>
  </tr>
  <tr>
    <td> … </td>
    <td> … </td>
  </tr>
</table>
VBA中的字符串连接(
&
)速度非常慢,因此,如果需要组合大量字符串,通常会使用类似于此的“stringbuilder”类来加速该过程

一般的想法是使用
Array()
存储单个字符串组件,然后在需要时使用
Join()
函数将所有字符串合并一次。添加字符串时,数组会自动调整大小。许多数组使用
“GrowBy”
功能(尽管此功能没有)当达到数组限制时,按静态大小或系数增加数组。这也可以提高性能,因为为每个字符串插入调用
ReDim Preserve

要回答您的问题,请假设您需要构建HTML文件的一部分。您可以使用如下所示的string类:

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()
使某人变暗 在此处设置sb=New StringBuilder的猜测。您尚未显示类名。 某人附加“一些字符串” 某人附加“另一个字符串” 某人附加“第三个字符串” .... sb.分隔符=“
” 我的HTMLFILE.给某人写ToString() 将打印以下内容:

某个字符串
另一个字符串
第三个字符串

这是一般的想法。通过使用数组,尽可能避免使用
&
,您应该会看到一些显著的性能改进。

这是一个老问题,OP可能已经继续。但是,当我查找有关此问题的内容时,这是我找到的页面。如果其他人发现它,这是我的尝试在一个更好的答案和一个链接到一个更好的答案

在这个问题或之前的任何答案中,我都找不到对这个问题的充分解释。在我的实验中,被接受的答案比内置的构建长字符串的方法表现更差

问题

假设我写:

StrVar = "abcde"
StrVar = StrVar & "fghij"
StrVar = StrVar & "klmno"
对于第一条语句,VBA解释器找到足够容纳5个字符的内存,将“abcde”写入该内存,并将StrVar指向该内存

对于第二条语句,VBA解释器找到足够容纳10个字符的内存,将StrVar的现有内容复制到该内存中,附加“fghij”,将StrVar指向该内存,并释放旧内存进行垃圾回收

对于第三条语句,VBA解释器找到足够容纳15个字符的内存,将StrVar的现有内容复制到该内存中,附加“klmno”,将StrVar指向该内存,并释放旧内存进行垃圾收集

关键是VBA字符串是不可变的,它们永远不会更改。相反,每次宏修改字符串时,都会为修改后的字符串找到新内存,并释放原始字符串的内存。对于一些字符串修改,不会对释放的内存做任何处理,因此不会明显浪费构建lon的时间但是,如果您经常这样做,解释器就会耗尽新内存,它必须调用垃圾收集器。垃圾收集器在所有内存中工作,确定哪些位仍在使用,哪些位未使用。它将所有仍在使用的位移动到一起,留下未使用的位作为新的可用内存控件返回给解释器,解释器继续处理新的字符串赋值,直到它再次耗尽新内存

如果要构建越来越长的字符串,解释器会越来越快地耗尽内存,直到宏变慢为爬行

我想要实现的目标、我的解决方案和更快的解决方案

我想将Excel范围转换为Html。忽略格式设置,我想创建如下字符串:

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
<table>
  <tr>
    <td> … </td>
    <td> … </td>
  </tr>
  <tr>
    <td> … </td>
    <td> … </td>
  </tr>
  <tr>
    <td> … </td>
    <td> … </td>
  </tr>
</table>
在我的笔记本电脑上,8000个电池所用的时间是4000个电池的3倍;16000个电池所用的时间是8000个电池的15倍,32000个电池所用的时间是16000个电池的9倍。如果你重复我的实验,你电脑上的持续时间的增加将取决于你有多少内存以及你在做什么

我并不期望需要转换32000个单元格。但是,对于这个实验,我只是转换单元格值。一旦我开始转换格式,字符串长度将显著增加,具有可接受性能的最大单元格数将下降

我的下一个想法是创建一个每行一个元素的字符串数组。将每个表行输出到字符串数组的不同元素,然后
连接
元素以创建完整的字符串。这与公认的答案中的想法相同。当我尝试这个想法时,32000个单元格花费了91秒。也许我可以减少t
  ' 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