For Each c In oSheet.Range("A1:A1000")
If InStr(c.Value, "VALUE") Then
c.EntireRow.Delete()
End If
Next
这只会删除指定范围内的一些行,问题是什么?
答案 0 :(得分:3)
以下是基于条件删除整行的两种常见模式。主要思想是在迭代时无法从集合中删除。这意味着Delete
不应出现在For Each
中。这在大多数编程语言中都是相当标准的,有些甚至会抛出错误来阻止它。
选项1 ,使用整数来跟踪行并使其从末尾开始工作。您需要向后退,因为这是避免跳过行的简单方法。可以前进,你只需要在删除时考虑不增加。
Sub DeleteRowsWithIntegerLoop()
Dim rng_delete As Range
Set rng_delete = Range("A1:A1000")
Dim int_start As Integer
int_start = rng_delete.Rows.Count
Dim i As Integer
For i = int_start To 1 Step -1
If InStr(rng_delete.Cells(i), "VALUE") > 0 Then
rng_delete.Cells(i).EntireRow.Delete
End If
Next i
End Sub
选项2 ,使用Union-Delete
模式构建一系列单元格,然后在最后一步中将它们全部删除。
Sub DeleteRowsWithUnionDelete()
Dim rng_cell As Range
Dim rng_delete As Range
For Each rng_cell In Range("A1:A1000")
If InStr(rng_cell, "VALUE") > 0 Then
If rng_delete Is Nothing Then
Set rng_delete = rng_cell
Else
Set rng_delete = Union(rng_delete, rng_cell)
End If
End If
Next
rng_delete.EntireRow.Delete
End Sub
有关代码的说明
对于选项2,当从第一个项目开始时,有一个额外的条件来创建rng_delete
。 Union
不适用于Nothing
引用,因此我们先检查一下,如果是,Set
查看第一项。所有其他人都通过Set
行获得Union
。
<强>偏好强>
在两者之间进行选择时,我总是更喜欢选项2,因为我更喜欢在Excel中使用Ranges
而不是使用计数器迭代Cells
。这有一些限制。第二个选项也适用于不连续的Ranges
以及所有其他各种奇怪的Ranges
(例如,在调用SpecialCells
之后),当您不确定自己将使用哪些数据时,它可以使其有价值处理。
<强>速度强>
我不确定速度比较。如果ScreenUpdating
并且启用了计算,则两者都可能很慢。第一个选项使N-1
调用Delete
,而第二个选项执行单个选项。 Delete
是一项昂贵的操作。但是,选项2会对N-1
和Union
进行Set
次调用。我认为它比基于它的第一个更快(它似乎在这里),但我没有描述它。
最后注释:InStr
返回一个整数,指示找到值的位置。我总是喜欢在这里明确布尔covnersion并与>0
进行比较。
答案 1 :(得分:1)
不要使用循环,请使用AutoFilter
Sub Recut()
Dim ws As Worksheet
Dim rng1 As Range
Set ws = ActiveSheet
Set rng1 = ws.[A1:A100]
ws.AutoFilterMode = False
Application.ScreenUpdating = False
With rng1
.AutoFilter Field:=1, Criteria1:="*VALUE*"
`assuming A1 is a header, and checking for at least 1 match on the filtered string
If .SpecialCells(xlCellTypeVisible).Cells.Count > 1 Then .Offset(1, 0).Resize(rng1.Rows.Count - 1, 1).EntireRow.Delete
End With
ws.AutoFilterMode = False
Application.ScreenUpdating = True
End Sub