奇怪的单元格地址行为非连续的范围:VBA
当我在Excel中遇到一些奇怪的VBA行为时,我试图回答这个问题 。 我写了一个非常简单的子来演示这个问题:
Sub debugAddresses(rng As Range) Debug.Print "Whole range: " & rng.Address Dim i As Long For i = 1 To rng.Cells.Count Debug.Print rng.Cells(i).Address Next i End Sub
我遍历范围对象中的每个单元格,并打印它的地址,简单的权利?
debugAddresses Range("B2:B3") ' Result as expected: ' >> Whole range: $B$2:$B$3 ' >> $B$2 ' >> $B$3
但是,对于不连续的范围,我会得到一些奇怪的行为:
debugAddresses Range("A1,B2") ' Strange behaviour when getting addresses of individual cells: ' >> Whole range: $A$1,$B$2 ' >> $A$1 ' >> $A$2
任何人都可以摆脱这个光? 具体而言, 为什么可以用于索引连续范围的Cells
对象似乎只是扩展了第一个选定的Area
。
编辑:可能值得注意的是,通过实际的单元格区域对象使用For Each
循环给出了预期的结果*
Sub debugAddresses2(rng As Range) Debug.Print "Whole range: " & rng.Address Dim c As Range For Each c In rng Debug.Print c.Address Next c End Sub
* 请参阅我的答案,以获得对更强大的解决scheme的评论,因为这(显然)可能不总是给出预期的结果
尝试使用下面修改的Sub debugAddresses
代码:
Sub debugAddresses(rng As Range) Dim RngA As Range Dim C As Range For Each RngA In rng.Areas For Each C In RngA.Cells Debug.Print C.Address Next C Next RngA End Sub
这里是你的代码“固定” 。 通过只增加一个For循环
Sub debugAddresses(rng As Range) Debug.Print "Whole range: " & rng.Address For Each r In rng ' this loops through the range even if separated cells Dim i As Long For i = 1 To r.Cells.Count 'changed to r instead of rng Debug.Print r.Cells(i).Address 'changed to r instead of rng Next i Next r End Sub
所以.Range
通过input单元地址ex来工作。 "B1"
,或者通过使用R1C1
表示行列ex。 1,2。
但是你不能在.Range中使用一个R1C1
,因为这里的范围是一个单元格的范围。 所以要在.Range
正确使用R1C1
,你必须指定2个。
所以.Range("B5:B10")
等于Range(Cells(5,2),Cells(10,2))
你所做的是指定一个范围,然后从那个使用单元格创build另一个范围。 非常像抵消 。
因此Range("A1,B2")
然后添加Cells(1)
然后Cells(2)
将行添加到“A1”的第一个范围或偏移。
Sub selector() Set Rng = Range("A1") Rng.Select Rng.Cells(4, 4).Select End Sub
这抵消了A1的4列和4列
看来Florent的评论是在正确的方向,而且这种方法正在扩展范围对象内的第一个Area
。
在连续范围内(例如"A1:B5"
, "C10:C100"
),以下方法在给定范围rng
中的每个单元格上循环。
Dim j As Long For j = 1 To rng.Cells.Count Debug.Print rng.Cells(j).Address Next j
然而,在不连续的范围内,这似乎是等同的(或简写为 )
For j = 1 To rng.Cells.Count Debug.Print rng.Areas(1).Cells(j).Address Next j
在文档中似乎没有直接提到这一点,但是通过查看VBA编辑器的本地浏览器来绘制是一个明智的结论。
在范围对象rng
,有一个Cells
属性,它只包含一个“Item”,它是第一个Area
。 所以这是合理的假设这个项目是什么.Cells(j)
有权访问。
在rng
我们还可以看到Areas
属性,其中包含2个项目(在本例中)等于我的非连续Areas
中的Areas
数量。
所以rng.Cells(j)
正在访问rng
的第一个区域内的第j
个元素。 由于.Cells()
可以超出rng
的原始大小,我们可以看到rng
以外的单元格列出的地址。
解决scheme:
- 要么确保你使用
For Each
循环直接遍历rng
的range对象,如问题所示。 - 或者循环遍历每个区域,然后遍历该区域内的每个单元格。
第一个选项更简洁,但是Shai指出,要完全确定,最可靠的方法就是做两个For Each
循环,因为可能会有更复杂的边缘情况,而这些边界情况不会被单个循环捕获。