当前位置:首页 > 科技 > 正文

VBA实战技巧精粹014:关于Range总结

1、如何复制

按平时的操作习惯可以知道,只需定位第1个位置即可。

'如果想通过复制/粘贴方式呢,只需指定第1个单元格即可.
With Workbooks('验证Range.xls').Sheets(2)
.Range('A1').CurrentRegion.Copy Destination:=Workbooks('book2.xls').Sheets(3).Range('A1')
End With

当然也可以通过直接赋值的方法来实现复制,但此时就要注意了,必须保证两块区域的大小是相同的。这点可以通过resize及计算出待复制区域的行数及列数来确定。

'如果想直接赋值 , 必须保证目标区域与源区域的大小一致才可以.以下代码验证通过
With Sheets(1).Range('A1').CurrentRegion
Sheets(3).Range('X1').Resize(.Rows.Count, .Columns.Count).Value = Sheets(2).Range('A1').CurrentRegion.Value
End With
2、如何获取指定列的列标(即如A、B、C、AA等表示)

利用chr函数可以实现A至Z的列标转换,但对于第27列以后的列标就没法转换了,代码如下:

Sub 获取指定列的字母()
Dim i As Integer, arr() As String
Debug.Print Cells(1, 27).Address
arr = Split(Cells(1, 27).Address, '$')
Debug.Print UBound(arr)
For i = 1 To UBound(arr)
Debug.Print arr(i)
Next i
End Sub

对于上面的代码,其中涉及到了split函数,解释如下:

描述

返回一个下标从零开始的一维数组,它包含指定数目的子字符串。

语法

Split(expression[, delimiter[, limit[, compare]]])

Split函数语法有如下命名参数:

部分 描述
expression 必需的。包含子字符串和分隔符的字符串表达式 。如果expression是一个长度为零的字符串(''),Split则返回一个空数组,即没有元素和数据的数组。
delimiter 可选的。用于标识子字符串边界的字符串字符。如果忽略,则使用空格字符(' ')作为分隔符。如果delimiter是一个长度为零的字符串,则返回的数组仅包含一个元素,即完整的 expression字符串。
limit 可选的。要返回的子字符串数,–1表示返回所有的子字符串。
compare 可选的。数字值,表示判别子字符串时使用的比较方式。关于其值,请参阅“设置值”部分。



设置值

compare参数的设置值如下:

常数 描述
vbUseCompareOption –1 Option Compare语句中的设置值执行比较。
vbBinaryCompare 0 执行二进制比较。
vbTextCompare 1 执行文字比较。
vbDatabaseCompare 2 仅用于Microsoft Access。基于您的数据库的信息执行比较。

针对代码中用到的split函数来看,首先明确split函数返回一个一维数组,代码的用法就是对$**$***的情况,利用$作为分隔符,将其中的**及***作为一维数组的元素来处理,由于其返回一个一维数组,所以直接在表达式后接(1)表示提取这个一维数组的第1个元素(实际就是第2个),因为这个一维数组的下标是从0开始的。这样的话,上面的代码就没有必要再再返回结果赋值给数组变量arr了,因为其本身就是数组,可以直接引用嘛。

Sub 获取指定列的字母()
Debug.Print Cells(1, 27).Address
Debug.Print Split(Cells(1, 27).Address, '$')(1)
End Sub

返回AA即第27列的列标。

3、如何快速判断是否为合并单元格

利用rang对象的mergecells属性就可判断。
Sub 判断是否为合并单元格()
If Range('A1').MergeCells = True Then
Debug.Print '为合并单元格'
Range('A1').Value = 100
Else
Debug.Print '不是合并单元格'
End If
End Sub

利用mergecells属性可以判断单个单元格是否为合并单元格,但如果是一个包含多个单元格的区域的话,比如只有range('A1:A10')全是合并单元时才会得到正确的结果。为什么会这样呢?里面明明包含有合并单元格区域啊,虽然只是一部分。这个很好理解:mergecells属性只是用来判断你所选定的区域是否为合并单元格区域,这就要求必须是保持一致才可以的。

那如果所选定的区域只是部分含有合并单元格又如何判断呢?可以通过遍历的方法来判断,不过这样有点慢了,可以isNull函数来判断。解释如下:

返回 Boolean 值,指出表达式是否不包含任何有效数据 (Null)。

语法

IsNull(expression)

必要的 expression 参数是一个 Variant,其中包含数值表达式字符串表达式

说明

如果 expressionNull,IsNull 返回 True;否则 IsNull 返回 False。如果 expression 由多个变量组成,则表达式的任何作为变量组成成分的 Null 都会使整个表达式返回 True

Null 值指出 Variant 不包含有效数据。Null Empty 不同,后者指出变量尚未初始化。Null 与长度为零的字符串 (““) 也不同,长度为零的字符串指的是空串。

重要 使用 IsNull 函数是为了确定表达式是否包含 Null 值的。在某些情况下,希望表达式取值为 True,比如希望 If Var = NullIf Var <> Null 取值为 True,而它们总取值为 False。这是因为任何包含 Null 的表达式本身就是 Null,所以为 False

这样的话,利用IsNull函数来判断选定区域是否包含有合并单元格,即:如果range('A1:A3').mergecells属性为Null,恰好说明里面包含有合并单元格,若不为空,则说明里面未包含合并单元格。

代码如下:

Sub 判断区域内是否包含有部分合并单元格()
If IsNull(Range('A1:A3').MergeCells) Then
MsgBox '包含有合并单元格'
Else
MsgBox '不包含合并单元格'
End If
End Sub
由于A1:A2为合并单元格,但由于A3不是合并单元格,所以range('A1:A3').mergecells属性为null,而如果为null的话,那么isnull()函数就为true,故输出“包含有合并单元格”的提示。

实际上仔细想想,想判断是否有合并单元格的目的就是想找到单元格所在的位置并对其进行操作,比如解除合并等。那上面的代码感觉没有多少实用的价值,倒不如遍历更有价值,但上面的代码也有借鉴的意义,尤其是在大数据量的情况下,靠目视不大好看的时候这个就可显示出其价值了。

4、合并单元格且保留原有内容

基本的思路就是指定需要合并的单元格区域,利用遍历,将所有需要合并单元格的内容提取至一个变量中,然后合并,将变量赋值给合并后的单元格。

忽然想到一个问题:for each 对单元格遍历时是先行后列还是先列后行?猜一下:先行后列

Sub 合并单元格且保留原框内容()
Dim MyRange As Range, s As String, MeRange As Range
Set MyRange = Range('A1').CurrentRegion '将当前单元格区域赋给MyRange,返回对象为Range
For Each MeRange In MyRange
s = s & MeRange.Value
Next MeRange
Debug.Print s
Application.DisplayAlerts = False
MyRange.Merge
MyRange.Value = s
Application.DisplayAlerts = True
End Sub
上面的猜题结果正确!!因为Excel VBA的习惯就是先行后列。

5、取消合并单元格且在每个单元格里保留内容

为便于练习,先建立一个含有合并单元格的例子:

Sub 自动合并单元格并赋值()
Dim i As Integer, MyRange As Range
Application.DisplayAlerts = False
For i = 1 To 10
Set MyRange = Range(Cells(2 * i - 1, 1), Cells(2 * i, 1))
MyRange.Merge
MyRange.Value = i
Next i
Application.DisplayAlerts = True
End Sub
下面要做的工作就是在指定工作表中取消合并单元格,并且在每个单元格中保留内容

Sub 取消合并单元格并每个单元格均保留内容()
Dim totalR As Integer, i As Integer, Tt As String, Cnt As Integer
totalR = Range('A65536').End(xlUp).Row + 1 '合并后单元格在计数时少1个,故真正的行数应+1
For i = 1 To totalR
Debug.Print 'i=' & i
Tt = Cells(i, 1).Value
Cnt = Cells(i, 1).MergeArea.Count
Cells(i, 1).UnMerge
Range(Cells(i, 1), Cells(i + Cnt - 1, 1)).Value = Tt
i = i + Cnt - 1 '明白了!!
Next i
End Sub
上面的代码有个地方终于搞明白了,就是关于为什么i = i + Cnt - 1,而不是i=i+Cnt?这里给i重新赋值后,就到了下一次循环,本来如果i=i+Cnt正好是从下一个合并单元格的第1个单元格开始操作,但由于到了下一循环i会自动加上1,就导致跑到第2个单元格了,会出现漏取消的情况。而如果令i=i+Cnt-1的话,正好由于循环本身要给i加1正好可以实现从下一个合并单元格的第1个单元格开始。

6、合并相同内容的单元格

这个也经常用到,但首先要搞清楚,是要在保留现状的基础进行合并,还是先按要合并的内容排序后再进行合并。一般情况下都是先排序,即将相同的内容排在一起,然后进行合并单元格操作。

为了防止漏掉,可以从最后一个单元格开始倒序合并,这样可以有效的避免漏合并现象。

建立一个样表:

Sub 建立一系列相同内容的单元格()
Dim i As Integer
Columns(2).Delete '如何删除整列(第2列)啊?这不就可以了吗?
Rows(2).Delete '如何删除整行(第2行)啊?这也可以啊。
Columns(1).Insert '如何插入一整行(在第1列之前插入)?一样可现.
For i = 1 To 10
Range(Cells(2 * i - 1, 2), Cells(2 * i, 2)).Value = i
Next i
End Sub
合并相同内容单元格

Sub 合并相同内容单元格()
Dim totalR As Integer, i As Integer
totalR = Range('B65536').End(xlUp).Row
Application.DisplayAlerts = False
For i = totalR To 2 Step -1
If Cells(i, 2).Value = Cells(i - 1, 2).Value Then
Range(Cells(i - 1, 2), Cells(i, 2)).Merge
End If
Next i
Application.DisplayAlerts = True
End Sub

43 Things: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
BuzzNet: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
del.icio.us: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
Flickr: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
IceRocket: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
LiveJournal: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
Technorati: Excel, Excel VBA, Range, VBA, 爱好者, 程序设计, 工作表, 循环
今天你菊子曰了么?

有话要说...

取消
扫码支持 支付码