如何测试 Excel VBA 范围变量以引用整列..?

Posted

技术标签:

【中文标题】如何测试 Excel VBA 范围变量以引用整列..?【英文标题】:How can Excel VBA range variables be tested for references to entire columns..? 【发布时间】:2018-12-05 16:49:58 【问题描述】:

有哪些方法可以测试 Excel VBA 范围变量以引用整列?

我正在使用 Excel 2007 VBA,使用 For-Each 循环遍历 Range 变量。范围作为参数传递给函数。对单个单元格、单元格范围和整行的引用都可以。

例如,这些是okiedokie:

Range("A1")     'One cell
Range("A1:D4")  'Range of cells.
Range("10:20")  'Entire rows 10 through 20.

但是,如果任何范围都引用了整个列,它将把函数拖到一个急停的位置。例如,这些不是 okiedokie,需要对其进行测试和避免:

Range("A:A")
Range("A:Z")
Range("AA:ZZ")

我有几种方法可以做到这一点,每一种都看似合理,但也有弱点。该代码包含用于在具有数千行的工作表中搜索单元格的循环,因此速度至关重要。

以下是我能想到的三种方式,但我想知道是否还有其他方式..?

    最简单、最快的方法是计算行数。如果Range(x).Rows.Count=1048576,这是工作表中的最大行数。但是,如果 实际 行数正好是那个数字,或者如果偶然有多个重叠区域/范围,这将不起作用 所有这些加起来就是那个数字。两者都不太可能,但可能。此外,如果 Excel 的版本发生变化,该数字也可能发生变化,从而导致代码损坏。

    对 Range.Address(False,False) 的文本使用正则表达式匹配,其模式为 ([A-Z]1,3):([A-Z]1,3)。我认为这将是速度规模的媒介。

    使用 VBA 循环、If-Then 和字符串函数(例如 InStr()Mid())选择 Range.Address(False,False) 的文本。我认为这是最慢的方法。

【问题讨论】:

对于数字 1,不要硬编码行数,而是从 Range.Parent 获取 Rows.Count。另外,多个重叠行是什么意思? 范围。对不起,我说错了,错了……打错了。我纠正了错字。我试图传达的是一个 Range 变量可以塞进很多东西。具体来说,许多 Area 对象。嗯......也许不是很多,我似乎记得在我的实验中,Range(string) 中的字符串的限制是 255 个字符。但是任何人,考虑一下:Range("A1:D4, B2:E5")。这两个范围重叠。确实,Excel 会修复它并将其分解为矩形区域对象而不重叠,但我的函数将接受任何输入,因此重叠是可能的。 感谢 Range.Parent.Rows.Count 的建议;这适用于获得最大行数。在此之后,我在 Debug 模式下浏览了 Locals,我发现可以通过几种不同的方式找到它。 【参考方案1】:

您可以通过检查Range.AddressRange.EntireColumn.Address 来测试范围是否是对列的引用,如下所示:

If Range("AA:ZZ").Address = Range("AA:ZZ").EntireColumn.Address Then
    'This returns True
End If

If Range("AA1:ZZ4").Address = Range("AA1:ZZ4").EntireColumn.Address Then
    'This returns False
End If

【讨论】:

有趣。你提到的 .EntireColumn 让我思考,我意识到我必须改变处理这个问题的方式。无论我做什么,我的函数的工作方式,它都会接受范围引用的任何组合。通常我使用Intersect(UsedRange, Range(SomeRange)) 来约束循环活动,这可能适用于您建议的列测试。但是......我只需要考虑到函数可能最终达到最大行数的事实,并且要么用MsgBox 警告用户,要么让它完成工作。谢谢。【参考方案2】:

不确定我是否完全理解这个问题,但这可能对你有用:

Public Sub Test()
    Debug.Print RowCheck(ThisWorkbook.Worksheets("Sheet1").Range("A1:A10"))
End Sub

Public Function RowCheck(InputRange As Range)
    Dim u As Long 'used number of rows
    Dim x As Long 'max number of rows for any column
    Dim r As Long 'number of rows based on input range

    With InputRange
        u = Cells(Rows.Count, .Columns(1).Column).End(xlUp).Row
        r = .Rows.Count
        x = Rows.Count
    End With

    If r = x And u < r Then
        RowCheck = "A bad column reference provided"
    Else
        RowCheck = "This is a valid reference"
    End If
End Function

【讨论】:

【参考方案3】:

好的,在阅读了大家的建议后,我意识到无论我做什么,传递给我的函数的任何Range 对象都可能包含整个列引用任何重叠范围引用的组合结果 整个列被选中。

但在翻译中,这意味着...数据中的所有行,也就是 UsedRange。对于大量数据,UsedRange 实际上可能会在 1048576 处到达最后一行。传递给我的 FunctionRange 引用的任何组合可能会导致一个巨大的区域覆盖一整列,一直到最大行。

当然,这种情况发生的可能性非常低,但我确实喜欢在我的代码中涵盖所有基础。但这个谜题的关键是UsedRange。这将创建一个“合成最大最后一行”。如果GrandRange,由于没有更好的名称,覆盖了UsedRange 中的所有行,那么我的函数将无事可做,也没有数据可返回。所以一个简单的 IF-Then-Exit 应该会给我我正在寻找的解决方案:

If Intersect(UsedRange,LeGrandeRange).Rows.Count = UsedRange.Rows.Count Then
    'All rows in `UsedRange` are affected.
    'Nothing to do.
    Exit Function
Else
    'Do everything here.
    'Then exit normally.
    ...
    ...
    ...
Endif

【讨论】:

以上是关于如何测试 Excel VBA 范围变量以引用整列..?的主要内容,如果未能解决你的问题,请参考以下文章

[Excel VBA]单元格区域引用方式的小结

使用范围变量时未定义 Excel vba 变量

使用VBA在excel公式中增加包含单元格引用的变量

将命名范围值分配给变量(Excel VBA) - 新手

VBA-EXCEL 用变量定义范围

Excel VBA怎么实现整行/列的遍历