从(非常大的)字符串中快速删除不必要的空格

时间:2018-02-10 13:36:29

标签: excel vba performance trim removing-whitespace

我正在使用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

是否有更快的方法从“非常大”的字符串中删除空格?

2 个答案:

答案 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个空格。

(我虽然想了解为什么第一种方法错过了角色,但因为我知道我的字符串并没有遗漏任何东西,而且这个练习的目的是节省时间那太傻了!)