奇怪的单元格地址行为非连续的范围: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循环,因为可能会有更复杂的边缘情况,而这些边界情况不会被单个循环捕获。