Excel VBA: End(xlUp) 和 End(xlDown) 都在第 244 行结束,这是空白?

Excel VBA: End(xlUp) and End(xlDown) all end up at row 244, which is blank?

我用公式填充 B2:GQ244,复制范围并按值粘贴,然后按列对范围进行排序。 B8:GQ244中的单元格全部为空白。然后,我想从第 2 行开始逐列连接非空白单元格。为此,我需要找到每列中的最后一个非空白单元格。

出于某种原因,End(xlUp) 和 End(xlDown) 都给出了第 244 行,该行是空的。我不知道为什么。我认为文件可能已损坏。所以,我将两张纸和模块复制到一个新创建的工作簿中,但无济于事。有什么解释为什么 End(xlUp) 和 End(xlDown) 都给出了第 244 行?

.Range("B2:GQ244").Formula = "=IF(ISERROR(FIND( B,Sheet9!$H34)),"""",Sheet9!$I34)"

'paste by value to get rid of formulae

.Range("B2:GQ244").Copy
.Range("B2").PasteSpecial Paste:=xlPasteValues

'sort by column

Dim last_row As Long
Dim j As Long

For i = 2 To 200 Step 1

Range(.Cells(2, i), .Cells(245, i)).Sort key1:=.Cells(2, i), order1:=xlAscending

Next i

For i = 2 To 200 Step 1

last_row = .Cells(65536, i).End(xlUp).Row
last_row = .Cells(1, i).End(xlDown).Row

我无法证实你的发现。有一个空白的 ActiveSheet 和一个空白的 Sheet9,下面的代码用零 B2:GQ244 填充了 ActiveSheet。然后它将最后一行 xlUp 读取为 244,将 xlDown 读取为 2。这两个值都符合预期。也许您有一个禁止显示零的设置。但是,正如我在上面的评论中所解释的那样,显示为空白的单元格不一定是空白的,这也适用于包含由您的公式插入的 NullString 的单元格,即使随后删除了该公式,在其位置留下了空字符串。

Sub Examine()
    
    Dim last_row As Long
    Dim i As Long

    With ActiveSheet
        .Range("B2:GQ244").Formula = "=IF(ISERROR(FIND( B,Sheet9!$H34)),"""",Sheet9!$I34)"
        
        'paste by value to get rid of formulae
        
        .Range("B2:GQ244").Copy
        .Range("B2").PasteSpecial Paste:=xlPasteValues
        
        'sort by column
        
        For i = 2 To 200 Step 1
            Range(.Cells(2, i), .Cells(245, i)).Sort Key1:=.Cells(2, i), Order1:=xlAscending
            last_row = .Cells(.Rows.Count, i).End(xlUp).Row
            Debug.Print last_row            ' returns 244
            last_row = .Cells(1, i).End(xlDown).Row
            Debug.Print last_row            ' returns 2
        Next i
    End With
End Sub

因此,剩下的唯一谜团就是为什么 .Cells(1, i).End(xlDown).Row 给您的值为 244。事实并非如此。因此,解决方案必须在您的测试中,而不是在其结果中。将您的测试方法与我上面使用的方法进行比较。

下面的代码将删除列底部的所有空字符串以及包含零的字符串。

Sub ClearBlankCells()
    ' 146
    
    Dim Rng         As Range            ' working range
    Dim R           As Long             ' intermediate: row
    Dim C           As Long             ' loop counter: columns

    Application.ScreenUpdating = False
    With ActiveSheet
        With .Range("B2:GQ244")
            .Formula = "=IF(ISERROR(FIND( B,Sheet9!$H34)),"""",Sheet9!$I34)"
            ' replace formulas with their values
            .Copy
            .PasteSpecial Paste:=xlPasteValues
        End With
        Application.CutCopyMode = False

        For C = 2 To 200 Step 1
            Set Rng = .Columns(C)
            R = Application.Evaluate("SUMPRODUCT((" & Rng.Address & "<>"""")*(" & _
                                                      Rng.Address & "<>0)*1)")
            If R > 0 Then
                Set Rng = Range(.Cells(R + 1, C), .Cells(Rows.Count, C))
                Rng.ClearContents
            End If
            ' sort by column
'            Range(.Cells(2, C), .Cells(245, C)).Sort Key1:=.Cells(2, C), Order1:=xlAscending
        Next C
    End With
    Application.ScreenUpdating = True
End Sub

请注意,每列底部上方的数据块中不得包含空格或零,包括标题。

必须在删除此类单元格后进行排序,但我将排序说明变暗了,因为它在语法或概念上都是错误的。如果您需要对每一列进行排序,则语法错误,因为该语法对整个 sheet 进行了排序。另一方面,如果您想对整个 sheet 进行排序,则不必循环执行 200 次。

代码运行非常缓慢,这引起了两个观察结果。

  1. 它花费 99% 的时间来修复它在第一行造成的损坏。
  2. 它查看的数据范围远远大于实际合理要求的范围。没有人愿意看 sheet 200 列和 244 行。

因此必须有更好的方法来实现您想要的。