如何测试Excel VBA范围变量对整个列的引用。

时间:2018-06-26 21:49:22

标签: excel-vba vba excel

有什么方法可以测试Excel VBA范围变量对整个列的引用?

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

例如,这些是ookedokie:

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

但是,如果任何范围都引用了整个列,它将把函数向下拖动到停止状态。例如,这些不是ookedokie,需要对其进行测试并避免:

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

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

这是我可以想到的三种方法,但我想知道是否还有其他方法。.

  1. 最简单,最快的方法是对行进行计数。如果为Range(x).Rows.Count=1048576,则为工作表中的最大行数。但是,如果 actual 的行数恰好是该数字,或者偶然地有多个重叠的区域/范围,则行不通 全部加起来就是那个数字。两者均不太可能,但可能。另外,如果Excel的版本更改了,那么该数字也可能更改,从而使代码损坏。

  2. 使用RegEx匹配范围为([A-Z]{1,3}):([A-Z]{1,3})的模式的Range.Address(False,False)文本。我认为这将是速度范围的一种媒介。

  3. 使用VBA循环If-Then以及诸如InStr()Mid()之类的字符串函数来选择Range.Address(False,False)的文本。我认为这将是最慢的方法。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

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

但是在翻译中,这意味着...数据中的所有行,也称为UsedRange。可能会有大量数据,UsedRange可能实际上到达了1048576的最后一行。并且Range引用的任何组合都传递给了我的Function 可能结果在覆盖整个列的最大区域中一直到最大行。

当然,发生这种情况的可能性很小,但是我确实希望覆盖代码中的所有基础。但是,这个难题的关键是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