ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

EH搜索     
EH云课堂-专业的职场技能充电站 Excel转在线管理系统,怎么做看这里 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
Excel不给力? 何不试试FoxTable! Excel 2016函数公式学习大典 高效办公必会的Office实战技巧 免费下载Excel行业应用视频
300集Office 2010微视频教程 Tableau-数据可视化工具 精品推荐-800套精选PPT模板,点击获取 ExcelHome出品 - VBA代码宝免费下载
你的Excel 2010实战技巧学习锦囊 欲罢不能, 过目难忘的 Office 新界面 Excel VBA经典代码实践指南
查看: 6536|回复: 25

[讨论] 匪夷所思的Range()合并区域赋值问题

[复制链接]

TA的精华主题

TA的得分主题

发表于 2013-12-11 22:29 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:Range对象
1==========================================================
问题来源于帖子: 很简单的批量写入数值的代码怎么写?--By coben_hb
像这样类似的代码该怎么写?
Sheets(1).Range("c1:c100", "b1:b100", "d1:d100").Value = Sheets(1).Range("a1:a100").Value

2==========================================================
不难看出,Range()的写法有问题,各区域名称应该合并为一个字符串:
Sheets(1).Range("c1:c100,b1:b100,d1:d100").Value = Sheets(1).Range("a1:a100").Value
但测试的结果却出人意料,实在出人意料!
1.jpg

3==========================================================
通过。。。。。。,最后发现一个规律。
要填充的数据源Range("a1:a100").Value是一个1列100行的二维数组,填充到Range(区域1,区域2,区域3,区域……)时,奇数位置的区域“区域1”、“区域3”……与数据源相同,偶数位置的区域“区域2”、“区域4”……却是转置后的水平数组。
可用下面的代码测试一下:
Range("b1:b5,d1:h1,j1:j5,l1:p1,r1:r5").Value = Range("a1:a5").Value
结果为:
2.jpg

4==========================================================
既然如此,那前面问题的答案可以是:
Sheets(1).Range("c1:c100,b1,b1:b100,d1,d1:d100").Value = Sheets(1).Range("a1:a100").Value
把原来三个区域全部写到奇数位置上,偶数位置随便写一个占个位。

5==========================================================
前面测试的两个例子都是N行1列的数组,如果n行n列会怎样,简单举例,如果把A1:B5填充到若干个区域,会出现什么情况?
代码:Range("d1:e5,g1:k2,m1:n5,p1:t2").Value = Range("a1:b5").Value
我以为会得到下面的结果:
3.jpg
其实不是:
4.jpg
奇怪,太奇怪了。你觉得呢?

6==========================================================
谁给我一个答案?

TA的精华主题

TA的得分主题

发表于 2013-12-12 00:02 | 显示全部楼层
哦,还是大师专业以及细心,原来如此,那同样是我的这个问题就有了答案了,http://club.excelhome.net/thread-1079744-1-1.html

TA的精华主题

TA的得分主题

发表于 2013-12-12 08:55 | 显示全部楼层
Sub g()
arr = Array("a1:a5", "a10:a14", "a18:a22")
For i = 0 To UBound(arr)
    Range(arr(i)).Value = Range("i1:i5").Value
Next i
End Sub
假设原数据在I1:I5
个人觉得也可采取这样的方式

TA的精华主题

TA的得分主题

发表于 2013-12-12 21:45 | 显示全部楼层
本帖最后由 liu-aguang 于 2013-12-13 08:06 编辑

版主发现的问题,的确有趣,并匪夷所思.作了以下几项测试但没有找到原因:
1.Sheets(1).Range("c1:c100,b1,b1:b100,d1,d1:d100")返回的是一个由三个区域组成的合并区域;
2.union(range("c1:c100"),range("b1:b100"),range("d1:d100"))返回的是一个区域;如果三个区域互不相邻则返回三个区域.
3.用单个值填充时,都能得到相同的希望的结果;用一列数填充时,如果合并区域是一个,如本例用union返回,会得到楼主希望的结果.
    如果合并区域由多个区域组成,无论是1.的Rang返回,还是union返回,则会出现版主发现的情形.
4.用二列数据填充时,不论那种方式返回,如果合并区域是一个区域组成,则只按二列数据填充一次数据;如果合并区域是多个区域组成,则出现版主发现的情形.
5.以上两种方式返回的多区域组成的合并区域,如果分别对每一个区域进行数组填充,则出现可以预见的正常效果.
看来只有微软才知道数组在填充合并区域时,它的计算引擎是怎样工作的了.

TA的精华主题

TA的得分主题

发表于 2013-12-12 22:11 | 显示全部楼层
本帖最后由 lee1892 于 2013-12-13 09:52 编辑

可以理解为,源数据区域先行后列的形成一个一维虚拟数组,被填充区域按先行后列的顺序,由这个虚拟数组中取数填充。

Range对象的帮助是怎么写的?哪位贴个全的?

TA的精华主题

TA的得分主题

发表于 2013-12-13 09:52 | 显示全部楼层
本帖最后由 lee1892 于 2013-12-13 10:01 编辑

Excel 2003 测试结果,以下只讨论Range属性的两个参数为文本形式:
1、Range属性只接受 最多 2 个参数,下述代码报错
  1. ActiveSheet.Range("A1:A5", "B1:B5", "C1:C5")
复制代码
2、Range属性的第 2 个参数字符串不能使用合并区域操作符(逗号)和相交区域操作符(空格),下述代码报错
  1. ActiveSheet.Range("A1:A5", "B1:F5, G1:H5")
  2. ActiveSheet.Range("A1:A5", "B1:B5 C1:C5")
复制代码
3、为区域的左上角或右下角,取决于第 1 个参数和其相对位置:
  1. ActiveSheet.Range("B1:B5", "H1:H5") 等价于 ActiveSheet.Range("B1:H5")
  2. ActiveSheet.Range("F1:F5", "C1:C5") 等价于 ActiveSheet.Range("C1:F5")
复制代码
4、如果第 1 个参数中包含有合并或相交区域操作符,则不再接受第 2 个参数,下述代码报错
  1. ActiveSheet.Range("A1:A5, B1:B5", "C1:C5")
  2. ActiveSheet.Range("A1:C5, B1:D5", "F1:F5")
复制代码
5、3个区域操作符的优先级:包括(冒号)> 相交(空格)> 合并(逗号),可以使用括号确定优先计算
  1. ActiveSheet.Range("B1:D5 C1:G5,F1:F5") 等价于 ActiveSheet.Range("C1:D5,F1:F5")
  2. ActiveSheet.Range("B1:D5,C1:G5 F1:F5") 等价于 ActiveSheet.Range("B1:D5,F1:F5")
  3. ActiveSheet.Range("(B1:D5,C1:G5) F1:F5") 等价于 ActiveSheet.Range("F1:F5")
复制代码
6、并列的合并操作符,奇数位正常,偶数位异常,这个特点很莫名其妙,因为其内部的顺序是一致的,下述代码的输出可以说明
  1. For Each oRng In ActiveSheet.Range("A1:B3, D1:E3")
  2.     Debug.Print oRng.Address
  3. Next
  4. 输出为:
  5. $A$1
  6. $B$1
  7. $A$2
  8. $B$2
  9. $A$3
  10. $B$3
  11. $D$1
  12. $E$1
  13. $D$2
  14. $E$2
  15. $D$3
  16. $E$3
复制代码
貌似微软也没有对此有任何特殊说明,只能这么记着就是了。下述代码产生的效果,如楼主描述的一样
  1. ActiveSheet.Range("D1:E5,G1:H5,J1:K5,M1:N5").Value = ActiveSheet.Range("A1:B5").Value
复制代码

未命名.PNG

不过我们可以确定的是二维内存数组的元素顺序,以上图为例,下述代码输出的是顺序排列的1~10,这和前面反映的单元格顺序是不同的
  1. arr = ActiveSheet.Range("A1:B5").Value
  2. For Each i In arr
  3.     Debug.Print i
  4. Next
复制代码



TA的精华主题

TA的得分主题

 楼主| 发表于 2013-12-13 10:22 | 显示全部楼层
Excel 开发人员参考
Worksheet.Range 属性

返回一个 Range 对象,它代表一个单元格或单元格区域。语法
表达式.Range(Cell1, Cell2)
表达式   一个代表 Worksheet 对象的变量。
参数
名称必选/可选数据类型说明
Cell1必选Variant区域名称。必须为采用宏语言的 A1 样式引用。可包括区域操作符(冒号)、相交区域操作符(空格)或合并区域操作符(逗号)。也可包括货币符号,但它们会被忽略掉。您可以在区域中任一部分使用局部定义名称。如果使用名称,则假定该名称使用的是宏语言。
Cell2可选Variant区域左上角和右下角的单元格。可以是一个包含单个单元格、整列或整行的 Range 对象,或者也可以是一个用宏语言为单个单元格命名的字符串。

说明

如果在没有对象识别符时使用,则该属性是 ActiveSheet.Range 的快捷方式(它返回活动表的一个区域,如果活动表不是一张工作表,则该属性无效)。
当应用于 Range 对象时,该属性与 Range 对象相关。例如,如果选中单元格 C3,那么 Selection.Range("B1") 返回单元格 D3,因为它同 Selection 属性返回的 Range 对象相关。此外,代码 ActiveSheet.Range("B1") 总是返回单元格 B1。

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-12-13 10:22 | 显示全部楼层


示例

此示例将 Sheet1 上 A1 单元格的值设置为 3.14159。
Visual Basic for Applications
Worksheets("Sheet1").Range("A1").Value = 3.14159

此示例在 Sheet1 的 A1 单元格中创建一个公式。
Visual Basic for Applications
Worksheets("Sheet1").Range("A1").Formula = "=10*RAND()"

此示例在 Sheet1 上的单元格区域 A1:D10 中进行循环。如果某个单元格的值小于 0.001,则此代码将用 0(零)来取代该值。
Visual Basic for Applications
For Each c in Worksheets("Sheet1").Range("A1:D10")    If c.Value < .001 Then        c.Value = 0    End IfNext c

此示例在名为“TestRange”的区域上进行循环,并显示该区域中空白单元格的个数。
Visual Basic for Applications
numBlanks = 0For Each c In Range("TestRange")    If c.Value = "" Then        numBlanks = numBlanks + 1    End IfNext cMsgBox "There are " & numBlanks & " empty cells in this range"

此示例将 Sheet1 中单元格区域 A1:C5 上的字体样式设置为斜体。此示例使用 Range 属性的语法 2。
Visual Basic for Applications
Worksheets("Sheet1").Range(Cells(1, 1), Cells(5, 3)). _    Font.Italic = True


&#169; 2010 Microsoft Corporation。保留所有权利。

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-12-13 10:23 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-12-13 10:28 | 显示全部楼层
lee1892 发表于 2013-12-13 09:52
Excel 2003 测试结果,以下只讨论Range属性的两个参数为文本形式:
1、Range属性只接受 最多 2 个参数,下 ...

Range属性只接受 最多 2 个参数。当两个参数时,第一个参数为区域左上角,第二个参数为区域右下角,最后形成一个区域。
Range("A1:A5",  "C1:C5")等效于Range("A1",  "C5"),等效于Range("A1:C5"),总共包含15个单元格。Range("A1:A5,C1:C5")与Range("A1:A5",  "C1:C5")不一样,它引用的是两个不相邻的区域A1:A5和C1:C5,是一个合并区域,总共包含10个单元格。

测试:
debug.Print Range("A1:A5",  "C1:C5").Address
$A$1:$C$5
debug.Print Range("A1:A5",  "C1:C5").Count
15


debug.Print Range("A1:A5,C1:C5").Address
$A$1:$A$5,$C$1:$C$5
debug.Print Range("A1:A5,C1:C5").Count
10


您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关注官方微信,高效办公专列,每天发车

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2019-8-18 21:59 , Processed in 0.107846 second(s), 15 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2020 Wooffice Inc.

   

沪公网安备 31011702000001号 沪ICP备11019229号

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:徐怀玉律师 李志群律师

快速回复 返回顶部 返回列表