对于每个Next循环意外跳过某些条目

时间:2014-07-01 17:00:32

标签: excel vba excel-vba foreach

我一直在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

3 个答案:

答案 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循环合并到你的代码中,它应该可以工作。