如何使用 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
第一个没问题,但有很多问题:
- 它花费的时间是单个替换的两倍
- 并不总是很清楚它是崩溃了,还是继续工作
- 如果它真的崩溃了,我会留下一些包含 -@- 的单元格,这并不总是很明显,并且该工具应该可以被无法理解的人使用 VBA.
所以我的问题:
- 有没有办法只使用一个替换来做到这一点?为什么 replace 可以用双替换,而不是单替换?
- 如果第一个不可行,那么如果代码崩溃,有没有办法'rolling back'替换?
- 有没有一种方法可以更新状态栏以显示替换有多远以证明代码是 运行(很像 运行 替换 Excel 本身) ?
- 或者是否有更好的方法来完成这一切?
提前致谢!
编辑:不幸的是,由于正在处理数据,我需要保留格式,包括前导零
编辑:这是我正在查看的数据类型的示例。我想替换零长度字符串(它们是没有任何值的非空白单元格),因此它们是真正的空白单元格。
您的单元格可以包含 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 可能会产生比它解决的问题更多的问题
我在 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
第一个没问题,但有很多问题:
- 它花费的时间是单个替换的两倍
- 并不总是很清楚它是崩溃了,还是继续工作
- 如果它真的崩溃了,我会留下一些包含 -@- 的单元格,这并不总是很明显,并且该工具应该可以被无法理解的人使用 VBA.
所以我的问题:
- 有没有办法只使用一个替换来做到这一点?为什么 replace 可以用双替换,而不是单替换?
- 如果第一个不可行,那么如果代码崩溃,有没有办法'rolling back'替换?
- 有没有一种方法可以更新状态栏以显示替换有多远以证明代码是 运行(很像 运行 替换 Excel 本身) ?
- 或者是否有更好的方法来完成这一切?
提前致谢!
编辑:不幸的是,由于正在处理数据,我需要保留格式,包括前导零
编辑:这是我正在查看的数据类型的示例。我想替换零长度字符串(它们是没有任何值的非空白单元格),因此它们是真正的空白单元格。
您的单元格可以包含 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 可能会产生比它解决的问题更多的问题