我一直在Excel中编写宏来扫描记录列表,在内容中找到“CHOFF”的任何单元格,复制包含它的行,然后将这些单元格粘贴到另一张表格中。它是格式化报告的较长代码的一部分。
它工作得很好,除了“For Each”循环一直在跳过一些看似随意的条目。它不是每隔一行,我尝试过不同的排序方式,但是无论如何都会跳过相同的单元格,所以它似乎不是关于单元格的顺序。我尝试使用InStr而不是cell.value,但仍然跳过相同的单元格。
你知道是什么导致代码只是不识别散布在范围内的一些细胞吗?
有问题的代码如下:
Dim Rng As Range
Dim Cell As Range
Dim x As Integer
Dim y As Integer
ActiveWorkbook.Sheets(1).Select
Set Rng = Range(Range("C1"), Range("C" & Rows.Count).End(xlUp))
x = 2
For Each Cell In Rng
If Cell.Value = "CHOFF" Then
Cell.EntireRow.Select
Selection.Cut
ActiveWorkbook.Sheets(2).Select
Rows(x).Select
ActiveWorkbook.ActiveSheet.Paste
ActiveWorkbook.Sheets(1).Select
Selection.Delete Shift:=xlUp
y = x
x = y + 1
End If
Next Cell
答案 0 :(得分:2)
For Each...Next
循环不会自动跟踪您删除的行。删除行时,Cell
仍指向同一地址(现在是原始行下面的行,因为已删除)。然后在下一轮循环时,Cell
移动到下一个单元格,跳过一个。
要解决此问题,您可以在Cell
语句中向上移动If
(例如,使用Set Cell = Cell.Offset(-1,0)
)。但我认为这是一个罕见的情况,其中一个简单的For
循环优于For Each
:
Dim lngLastRow As Long
Dim lngSourceRow As Long
Dim lngDestRow As Long
Dim objSourceWS As Worksheet
Dim objDestWS As Worksheet
Set objSourceWS = ActiveWorkbook.Sheets(1)
Set objDestWS = ActiveWorkbook.Sheets(2)
lngLastRow = objSourceWS.Range("C" & objSourceWS.Rows.Count).End(xlUp).Row
lngDestRow = 1
For lngSourceRow = lngLastRow To 1 Step -1
If objSourceWS.Cells(lngSourceRow, 3).Value = "CHOFF" Then
objSourceWS.Rows(lngSourceRow).Copy Destination:=objDestWS.Cells(lngDestRow, 1)
objSourceWS.Rows(lngSourceRow).Delete
lngDestRow = lngDestRow + 1
End If
Next lngSourceRow
这会向后循环(根据Portland Runner的建议),以避免对删除的行做任何事情。它还会在您的代码中整理其他一些内容:
Select
,最好不要(请参阅this question了解原因)Range.Copy
内指定目的地,而不必单独选择并粘贴x = x + 1
很好)Long
而不是Integer
,因为Excel电子表格中的行数多于Integer
可以处理的行数(至少65536与32767相比)最大Integer
)显然测试它仍然能满足您的需求!
答案 1 :(得分:1)
尝试使用Selection.Copy而不是Selection.Cut
如果必须删除这些行,可以在循环内标记行(例如在未使用的单元格中写入内容),然后在完成主循环后将其删除。
问候
答案 2 :(得分:-1)
当我尝试删除某些行时,我遇到了类似的问题。我克服它的方法是使用以下方法多次遍历循环:
For c = 1 To 100
Dim d As Long: d = 1
With Sheets("Sheet")
For e = 22 To nLastRow Step 1
If .Range("G" & e) = "" Or .Range("I" & e) = "" Then
.Range("G" & e).EntireRow.Delete
.Range("I" & e).EntireRow.Delete
d = d + 1
End If
Next
End With
c = c + 1
Next
所以,基本上如果你将我的代码中的外部for循环合并到你的代码中,它应该可以工作。