如何使用 VBA 删除 Excel 中的零长度字符串?

How do I remove zero-length strings in Excel using VBA?

我在 VBA 中为 Excel 创建了一个工具,它根据一些标准分析我们收到的 .xlsx 文件。其中之一是数据集中空单元格的数量。不过,不幸的是,我注意到我们收到的许多文件都包含带有零长度字符串的单元格,这些单元格被 "incorrectly" 计为非空单元格。

如果我能够从文件中删除这些,实际上对整个过程非常有益。

我用谷歌搜索了很多这个问题,但到目前为止我能找到的唯一解决方案是遍历 sheet 中的所有单元格(我也尝试过只使用常量,并且还使用find 找到所有的zls)。这不是很有效,因为 worksheets 中有大量数据。 编辑:我也尝试过 UsedRange.values = UsedRange.values 方法,但这会删除我需要的前导零。

我还发现这行得通(-@- 是一个随机字符串,不太可能是我数据中的单个单元格,如果存在,可以删除):

ws.UsedRange.Replace what:=vbNullString, replacement:="-@-", _
                            lookat:=xlWhole, MatchCase:=False
ws.UsedRange.Replace what:="-@-", replacement:="", _
                            lookat:=xlWhole, MatchCase:=False

但如果我只使用单个替换来做到这一点,它不会:

ws.UsedRange.Replace what:=vbNullString, replacement:="", _
                            lookat:=xlWhole, MatchCase:=False

第一个没问题,但有很多问题:

  1. 它花费的时间是单个替换的两倍
  2. 并不总是很清楚它是崩溃了,还是继续工作
  3. 如果它真的崩溃了,我会留下一些包含 -@- 的单元格,这并不总是很明显,并且该工具应该可以被无法理解的人使用 VBA.

所以我的问题:

  1. 有没有办法只使用一个替换来做到这一点?为什么 replace 可以用双替换,而不是单替换?
  2. 如果第一个不可行,那么如果代码崩溃,有没有办法'rolling back'替换?
  3. 有没有一种方法可以更新状态栏以显示替换有多远以证明代码是 运行(很像 运行 替换 Excel 本身) ?
  4. 或者是否有更好的方法来完成这一切?

提前致谢!

编辑:不幸的是,由于正在处理数据,我需要保留格式,包括前导零

编辑:这是我正在查看的数据类型的示例。我想替换零长度字符串(它们是没有任何值的非空白单元格),因此它们是真正的空白单元格。

您的单元格可以包含 return 空字符串的公式,也可以包含空字符串常量的单元格。清除第二种单元格:

Sub KillNullConstants()
    Dim cell As Range, Konstants As Range, rng As Range
    Set Konstants = ActiveSheet.UsedRange.Cells.SpecialCells(xlCellTypeConstants)
    Set rng = Nothing
    For Each cell In Konstants
        If Len(cell) = 0 Then
            If rng Is Nothing Then
                Set rng = cell
            Else
                Set rng = Union(rng, cell)
            End If
        End If
    Next cell

    If Not rng Is Nothing Then
        rng.ClearContents
    End If
End Sub

要清除 return 空字符串的公式单元格,只需更改 SpecialCells 代码行。

我知道这也是一个循环,但也许是一种更快的方法:

之前:

运行 样本数据上的代码:

Dim X As Double

Option Explicit

Sub Test()

Application.ScreenUpdating = False
Application.Calculation = xlManual

With ActiveWorkbook.Sheets(1).Range("A1:C7")
    For X = 1 To 3
        .AutoFilter Field:=X, Criteria1:=""
        .Columns(X).Offset(1, 0).SpecialCells(xlCellTypeVisible).Clear
    Next X
    .AutoFilter
End With

Application.Calculation = xlAutomatic
Application.ScreenUpdating = True

End Sub

之后:

将 sheet 读入 ADO 记录集,然后将记录集复制到新的 sheet 似乎可以解决此问题。试试这个 VBA 代码:

Sub copy_data()

Dim cn As Object
Set cn = CreateObject("ADODB.Connection")

With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & ThisWorkbook.FullName & ";" & _
        "Extended Properties=""Excel 12.0 Macro;IMEX=1;HDR=YES"";"
    .Open
End With

Dim rs As Object
Set rs = CreateObject("ADODB.Recordset")

rs.Open "SELECT * FROM [Sheet1$];", cn

Dim i As Integer
Dim fld As Object

With ThisWorkbook.Worksheets("Sheet2")
    .UsedRange.ClearContents

    i = 0
    For Each fld In rs.Fields
        i = i + 1
        .Cells(1, i).Value = fld.Name
    Next fld

    .Cells(2, 1).CopyFromRecordset rs
    .UsedRange.Columns.AutoFit
End With

rs.Close
cn.Close

End Sub

备注:

  • 更改代码中的 sheet 名称以匹配您的 sheet 名称 使用。您必须在您使用的 sheet 名称后放置一个 $ 符号 rs.Open。如果你的 sheet 被称为 "Data" 那么你会把 rs.Open "SELECT * FROM [Data$];", cn
  • 在连接字符串扩展属性中,HDR=YES 用于指定数据具有 headers。 ADO 可能会更改某些列名,如果它们包含 某些字符 - 主要是 . 字符,通常会 替换为 # 字符

潜在问题:

  • 您的数据需要大致采用 table 格式 - 即列名 在第 1 行中,每列名称下方的数据值
  • 数据中的任何公式都将转换为值
  • 不会复制单元格格式 - 但数字 格式化为文本将保持为 保留前导零的文本
  • 任何长度超过 255 个字符的单元格值文本都可能被截断 最多 255 个字符(如果需要可以解决这个问题)

根据您的数据,使用 ADO 可能会产生比它解决的问题更多的问题