【问题标题】:How can Excel VBA range variables be tested for references to entire columns..?如何测试 Excel VBA 范围变量以引用整列..?
【发布时间】: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")

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

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

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

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

  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,我发现可以通过几种不同的方式找到它。

标签: excel vba


【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 2017-10-31
      相关资源
      最近更新 更多