【问题标题】:For Each Next loop unexpectedly skipping some entries [duplicate]对于每个下一个循环意外地跳过一些条目[重复]
【发布时间】:2014-08-22 08:00:37
【问题描述】:

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

【问题讨论】:

  • 您是否单步执行了代码,尤其是在移动行时。我认为问题可能与您在迭代 Rng 时对其进行了修改有关。
  • 这些单元格中是否有空格?这通常是未清理数据的问题。您也可以尝试确保 Rng.Address 显示您期望它显示的内容。
  • 我已经完成了它,它做了我想要的,除了跳过一些它应该因为某种原因而捡起来。 Rng 在循环期间没有被修改,因为 x 变量不是范围的一部分(仅用于目标位置)。我还尝试了 InStr 以确保它不是空间问题,但没有任何问题,也没有帮助。这是来自数据提取,因此单元格非常一致。

标签: vba excel foreach


【解决方案1】:

For Each...Next 循环不会自动跟踪您删除了哪些行。当您删除一行时,Cell 仍然指向相同的地址(现在是原始地址下方的行,因为该地址已被删除)。然后在下一次循环中,Cell 移动到下一个单元格,跳过一个。

要解决此问题,您可以在 If 语句中将 Cell 上移一位(例如,使用 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 的建议)以避免对已删除的行执行任何操作。它还整理了代码中的其他一些内容:

  • 你不需要做任何Selecting,最好不要做(原因见this question
  • 您可以在Range.Copy 中指定目的地,而不必单独进行选择和粘贴
  • 您可以“就地”更改变量的值,而不必先将其分配给第二个变量(即x = x + 1 很好)
  • 对于包含行号的变量,您应该使用 Long 而不是 Integer,因为 Excel 电子表格中的行数超过了 Integer 可以处理的行数(至少 65536,而 Integer 的最大行数为 32767 )

显然测试它仍然可以满足您的要求!

【讨论】:

  • 我一定会试一试你的方法,但删除的东西不是问题。我认为这可能是导致它的原因,所以我将删除的内容取出并将其放在代码的全新部分中,但它没有帮助。无论在现场的位置如何,被跳过的那些每次都是相同的,并且它们并不总是跟随另一个被剪切和粘贴的。
  • 这段代码确实为我解决了这个问题。删除后跳过以下行不是问题,我不确定是什么,但是删除 for each 并用你的构造方式替换它,不管它是什么。
【解决方案2】:

尝试使用 Selection.Copy 而不是 Selection.Cut

如果您必须删除这些行,您可以在循环内标记这些行(例如在未使用的单元格中写一些东西),然后在完成主循环后将其删除。

问候

【讨论】:

  • 或者,自底向上迭代
【解决方案3】:

我在尝试删除某些行时遇到了类似的问题。我克服它的方法是使用以下方法多次迭代循环:

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

【讨论】:

  • 只有在你向后循环时才有效,从 lastrow 到 22 step -1。因为假设您删除了第 23 行,那么循环将跳过旧的第 24 行,现在称为 row23。
  • 谢谢,我将代码更改为自下而上,现在很好,我希望我早点想到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
  • 2021-08-27
相关资源
最近更新 更多