我有一个excel表,如下所示:
Name task date1 date2 date3 date4
John t1 d1
Lucy t2
Mary t3 d2 d3
我要删除第3列(即,来自date1
之后的列为空的行(例如本例中的Lucy)
我找到了下面的示例,我认为它很接近,但是不确定如何通过选择第三列之后的空行而不是整个行来修改它。
Sub DeleteAllEmptyRows()
Dim LastRowIndex As Integer
Dim RowIndex As Integer
Dim UsedRng As Range
Set UsedRng = ActiveSheet.UsedRange
LastRowIndex = UsedRng.Row - 1 + UsedRng.Rows.Count
Application.ScreenUpdating = False
For RowIndex = LastRowIndex To 1 Step -1
If Application.CountA(Rows(RowIndex)) = 0 Then 'Some logic to add here to choose range
Rows(RowIndex).Delete
End If
Next RowIndex
Application.ScreenUpdating = True
End Sub
有什么建议吗?谢谢。
答案 0 :(得分:1)
我想您所需要的就是首先计算使用范围内的最后一列,然后在循环内的CountA语句中使用它。
要计算最后一列,您可以在循环之前添加以下几行:
Dim LastColIndex As Integer: LastColIndex = UsedRng.Column - 1 + UsedRng.Columns.Count
If
语句将需要看起来像这样:
If WorksheetFunction.CountA(Range(Cells(RowIndex, 3), Cells(RowIndex, LastColIndex))) = 0 Then
这将从当前行的第三列开始检查非空值。
合并后的代码如下:
Sub DeleteAllEmptyRows()
Dim LastRowIndex As Integer
Dim RowIndex As Integer
Dim UsedRng As Range
Set UsedRng = ActiveSheet.UsedRange
LastRowIndex = UsedRng.Row - 1 + UsedRng.Rows.Count
Application.ScreenUpdating = False
Dim LastColIndex As Integer: LastColIndex = UsedRng.Column - 1 + UsedRng.Columns.Count
For RowIndex = LastRowIndex To 1 Step -1
If WorksheetFunction.CountA(Range(Cells(RowIndex, 3), Cells(RowIndex, LastColIndex))) = 0 Then
Rows(RowIndex).Delete
End If
Next RowIndex
Application.ScreenUpdating = True
End Sub
我还可以将For
循环更改为从2倒数而不是1,以避免可能删除标题行,但是我想这取决于您的口味:)
如果是幻影值...
有时,像元具有一个或多个空格作为其值时,像元具有的值用肉眼不可见,但通过Excel的COUNTA
函数进行计数。如果需要考虑这些情况,我们可以使用以下VBA功能单独检查每个单元:
Function IsBlankRange(ByRef rng As Range) As Boolean
'For faster processing, read in the entire range into a memory variable
' instead of reading in each cell value from Excel
Dim arr As Variant: arr = rng.Value
'If the range contains a single value, check it and exit
If Not IsArray(arr) Then 'With single-value ranges, arr will not be an array
IsBlankRange = Trim(arr & "") = ""
Exit Function
End If
'If we are here, the range contains an array of values,
' so we must loop through the array
'Assume the range is not blank
IsBlankRange = False
Dim arrLb1 As Long: arrLb1 = LBound(arr, 1)
Dim arrUb1 As Long: arrUb1 = UBound(arr, 1)
Dim arrLb2 As Long: arrLb2 = LBound(arr, 2)
Dim arrUb2 As Long: arrUb2 = UBound(arr, 2)
Dim i As Long, j As Long
For i = arrLb1 To arrUb1
For j = arrLb2 To arrUb2
'Return false (the value assumed above) on the first non-blank value
If Trim(arr(i, j) & "") <> "" Then Exit Function
Next
Next
'If we are here, no non-blank value was encountered, so the range is blank
IsBlankRange = True
End Function
此功能可用于将If WorksheetFunction.CountA(...) = 0
行更改为
If IsBlankRange(Range(Cells(RowIndex, 3), Cells(RowIndex, LastColIndex))) Then
简而言之,新过程如下所示:
Sub DeleteAllEmptyRows()
Dim LastRowIndex As Integer
Dim RowIndex As Integer
Dim UsedRng As Range
Set UsedRng = ActiveSheet.UsedRange
LastRowIndex = UsedRng.Row - 1 + UsedRng.Rows.Count
Application.ScreenUpdating = False
Dim LastColIndex As Integer: LastColIndex = UsedRng.Column - 1 + UsedRng.Columns.Count
For RowIndex = LastRowIndex To 1 Step -1
If IsBlankRange(Range(Cells(RowIndex, 3), Cells(RowIndex, LastColIndex))) Then
Rows(RowIndex).Delete
End If
Next RowIndex
Application.ScreenUpdating = True
End Sub
自然,还需要添加新的IsBlankRange
函数(可能在DeleteAllEmptyRows
代码下面)。如果该功能永远不会在其他任何地方使用,则可以将其设为模块私有。
但是,如果可以使用CONCAT ...
如果您拥有Excel 2019,可以简化IsBlankRange
函数,并且可以使用新的CONCAT
函数,该函数可以应用于范围:
Function IsBlankRange(ByRef rng As Range) As Boolean
IsBlankRange = Trim(WorksheetFunction.Concat(rng) & "") = ""
End Function
{https://www.excelfunctions.net/excel-concat-function.html}解释了CONCAT
函数
IsBlankRange
除了可以使用CONCAT
函数之外,还可以直接在If
循环内的For
语句中使用:
If Trim(WorksheetFunction.Concat(Range(Cells(RowIndex, 3), Cells(RowIndex, LastColIndex))) & "") = "" Then
但是,我认为将范围评估留在单独的函数中可以更轻松地根据所使用的Excel版本进行自定义,并且使If
语句更易于阅读。