我正在使用VBA中非常大(45,000,000个字符)的字符串,我需要删除多余的whitespace。
一个空格(又名ASCII代码32)没问题,但任何有两个或多个连续空格的部分应该减少到只有一个。
我发现了类似的问题here,尽管OP对“非常长的字符串”的定义是仅 39,000个字符。接受的答案是使用Replace
:
Function MyTrim(s As String) As String
Do While InStr(s, " ") > 0
s = Replace$(s, " ", " ")
Loop
MyTrim = Trim$(s)
End Function
我尝试了这种方法并且“工作”,但痛苦地慢:
Len In: 44930886 Len Out: 35322469 Runtime: 247.6 seconds
是否有更快的方法从“非常大”的字符串中删除空格?
答案 0 :(得分:5)
我怀疑性能问题是由于创建了大量的大型中间字符串。因此,任何在不创建中间字符串或少得多的情况下执行操作的方法都会表现得更好。
正则表达式替换很有可能。
Option Explicit
Sub Test(ByVal text As String)
Static Regex As Object
If Regex Is Nothing Then
Set Regex = CreateObject("VBScript.RegExp")
Regex.Global = True
Regex.MultiLine = True
End If
Regex.Pattern = " +" ' space, one or more times
Dim result As String: result = Regex.Replace(text, " ")
Debug.Print Len(result), Left(result, 20)
End Sub
输入字符串为4500万个字符大约需要一秒钟。
转轮:
Sub Main()
Const ForReading As Integer = 1
Const FormatUTF16 As Integer = -1 ' aka TriStateTrue
Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
Dim file As Object: Set file = fso.OpenTextFile("C:\ProgramData\test.txt", ForReading, False, FormatUTF16)
Dim text As String: text = file.ReadAll()
Set file = Nothing
Set fso = Nothing
Debug.Print Len(text), Left(text, 20)
Test (text)
End Sub
测试数据创建者(C#):
var substring = "××\n× ×× ";
var text = String.Join("", Enumerable.Repeat(substring, 45_000_000 / substring.Length));
var encoding = new UnicodeEncoding(false, false);
File.WriteAllText(@"C:\ProgramData\test.txt", text, encoding);
BTW-由于VBA(VB4,Java,JavaScript,C#,VB,...)使用UTF-16,空格字符是一个UTF-16代码单元ChrW(32)
。 (与ASCII相似或比较,是不必要的心理体操,如果作为ANSI [Chr(32)
]加入代码,在幕后进行不必要的转换,对不同的机器,用户和时间有不同的行为。)
答案 1 :(得分:1)
在VBA中,String
的大小仅限于 2 Billion Characters 。 " Replace
- Loop
"对于45百万字符串,上面的方法需要247秒,超过4分钟。
理论上,这意味着一个20亿字符串至少需要3个小时 - 如果它甚至没有崩溃就完成了 - 所以它并不完全实用。
Excel有一个内置的工作表函数Trim
与VBA's Trim
函数不一样。
工作表函数Trim
从文本中删除所有空格,除了单词之间的单个空格。
问题是Trim
与所有使用Application.WorksheetFunction
调用的函数一样,大小限制为 32,767 个字符,并且[不幸的是]即使用VBA 调用函数时也会应用,其字符串甚至不在单元格中。
然而,如果我们使用它来循环我们的"巨大的字符串"我们仍然可以使用该函数。分段,像这样:
编辑: 不要打扰这个垃圾(我的功能,下面)! 查看 RegEx 回答above。
Function bigTrim(strIn As String) As String Const maxLen = 32766 Dim loops As Long, x As Long loops = Int(Len(strIn) / maxLen) If (Len(strIn) / maxLen) <> loops Then loops = loops + 1 For x = 1 To loops bigTrim = bigTrim & _ Application.WorksheetFunction.Trim(Mid(strIn, _ ((x - 1) * maxLen) + 1, maxLen)) Next x End Function
在&#34; Replace
- Loop
&#34;使用的相同字符串上运行此函数方法产生很多更好的结果:
Len In: 44930886 Len Out: 35321845 Runtime: 33.6 seconds
这比&#34; Replace
- Loop
&#34;快了7倍多。方法,和成功删除了其他方法遗漏的624个空格。
(我虽然想了解为什么第一种方法错过了角色,但因为我知道我的字符串并没有遗漏任何东西,而且这个练习的目的是节省时间那太傻了!)☺