我正在尝试删除所有包含 #REF 文本的行。但是我在对象中出错。
我试图从循环中提取代码并工作。这怎么会发生?是嵌套循环吗?
1)不工作的代码
Sub FindDeleteLoop()
Dim wb1 As Workbook
Dim sh1 As Worksheet
Dim objcell As Range
Dim delrow As Long
Dim i As Long
Set wb1 = ActiveWorkbook
For Each sh1 In wb1.Worksheets
With sh1
RowCount = sh1.Cells.Find(What:="*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Row
For i = 1 To RowCount
On Error GoTo nextcom
Set objcell = sh1.Cells.Find(What:="*#REF*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
objcell.EntireRow.Delete
Next i
nextcom:
End With
Next
End Sub
然后我在第二个循环之外尝试了相同的操作,并
通过替换获得了2) 工作代码
For Each sh1 In wb1.Worksheets
和
Set sh1 = wb1.ActiveSheet
我只是不明白这样做的理由。
缩进极具误导性。让我们先修复它:
For Each sh1 In wb1.Worksheets
With sh1
RowCount = sh1.Cells.Find(What:="*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Row
For i = 1 To RowCount
On Error GoTo nextcom
Set objcell = sh1.Cells.Find(What:="*#REF*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
objcell.EntireRow.Delete
Next i
nextcom:
End With
Next
问题是错误状态永远不会被清除,所以无论何时Range.Find
返回Nothing
,下一条指令都是非法的:
objcell.EntireRow.Delete 'objcell is Nothing ~> error 91
因此,当 VBA 仍处于错误状态时,内部循环继续进行,On Error
因此忽略下一次迭代的语句 - 当下一次objcell.EntireRow
抛出错误 91 时,执行会突然停止。
解决方案是删除这些On Error
语句,并使用正常的流控制——也就是说,只有objcell
当你知道它持有一个有效的对象引用时才调用一个成员:
If Not objcell Is Nothing Then objcell.EntireRow.Delete
代码也有其他问题。Range.Find
正在搜索整个工作表:无需迭代每一行。
RowCount = sh1.Cells.Find(What:="*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Row
如果sh1
是空工作表,这将失败并显示错误 91 ,因为Row
成员调用将与Nothing
. 考虑这种更安全的方法:
RowCount = sh1.Cells(Rows.Count, 1).End(xlUp).Row
无论如何,我们并不真正关心行数是多少——我们可以继续搜索工作表,直到没有更多结果:
Do
Set objcell = sh1.Cells.Find(...)
If Not objcell Is Nothing Then objcell.EntireRow.Delete
Loop While Not objcell Is Nothing
但是回到错误的错误处理。
正如上面简要提到的,答案是“是”,但有一个警告:如果错误没有被实际处理,那么 VBA 不知道它回到了“快乐的道路”,并且在仍然处于错误状态的时候快乐地继续迭代.
所以问题是您的错误执行路径与正常执行路径交织在一起:每当您设置错误处理程序子例程时,您需要确保错误处理子例程只在错误状态下运行,并且要么实际处理错误状态或退出程序。
Err.Clear
在nextcom:
标签和End With
后面的标签之间添加将清除错误状态并且循环将起作用......但您仍然会有交织在一起的执行路径:如上所示,这表明您正在使用错误处理进行流控制,那就是使代码更难遵循。
这是糟糕的代码,执行路径解开仅用于说明目的(改用上面的Do...While
循环!)
For Each sh1 In wb1.Worksheets
With sh1
RowCount = sh1.Cells.Find(What:="*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Row
For i = 1 To RowCount
On Error GoTo ErrHandler
Set objcell = sh1.Cells.Find(What:="*#REF*", After:=sh1.Cells(1, 1), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
objcell.EntireRow.Delete
Next i
End With
nextcom: '<~ never jump back into a With...End With block
Next
Exit Sub '<~ "happy path" ends here
ErrHandler: '<~ "error path" starts here
Debug.Assert Err.Number = 91 'execution stops here if that isn't the case
Resume nextcom '<~ 'Resume' clears the error state
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句