本文介绍VBA中的布尔运算(即逻辑运算)、比较条件,以及If语句和Select语句的使用。
布尔运算
布尔(Boolean)运算就是逻辑(Logical)运算,只是在不同的环境中称呼不同。在Excel中称为逻辑运算,通过AND()、OR()等函数操作,在VBA代码中称为布尔运算,其数据类型为布尔类型,使用Boolean关键字声明,布尔类型的值只有True和False。
VBA中常用的布尔运算包括:
与运算,使用And运算符。需要两个运算数,当两个运算数都是True时,结果为True;否则计算结果为False。
或运算,使用Or运算符。需要两个运算数,有一个运算数为True时,运算结果为True;两个运算数都是False时,运算结果为False。
非运算,也称为取反运算,使用Not运算符。需要一个运算数,True取反为False,False取反为True。
异或运算,使用Xor运算符。需要两个运算数,两个运算数相同时结果为False,两个运算数不同时结果为True。
下面通过布尔运算封装一个判断年份是否为闰年的函数,在“工程”窗口中通过右键菜单“插入”>>“模块”添加一个新的模块,并命名为mComm,接下来会将一些常用的函数定义在此模块中。判断年份是否为闰年的代码如下。
VBA |
' 判断年份是否为闰年 Function isLeap(year As Integer) As Boolean isLeap = (year Mod 400 = 0) Or (year Mod 100 <> 0 And year Mod 4 = 0) End Function |
代码中,第一行使用英文单引号开始,此行会作为注释,并不是执行代码的一部分。VBA中的注释有两种形式,一是使用Rem关键字开始的行注释,二是英文单引号开始直到行结束的部分作为注释,单引号注释可以是一行,也可以在一行代码的最后。
isLeap()函数的定义中包含一个Integer类型的参数,用于带入年份数值;定义参数的括号后使用As关键字声明了函数的返回值类型,这里设置为Boolean类型,当年份是闰年时返回True,否则返回False。函数中直接使用函数名isLeap返回了判断闰年的条件,下面单独看一下:
VBA |
(year Mod 400 = 0) Or (year Mod 100 <> 0 And year Mod 4 = 0) |
判断是否为闰年时两种情况,只要满足其一即是闰年,两个条件使用Or运算符组合。第一种情况,即前一对圆括号中的条件,只要年份能够被400整除,也就是除以400的余数为0时,即为闰年。第二种情况需要同时满足两个条件,在后一对括号中使用And运算符组合,条件是年份不能被100整除,但能被4整除即是闰年。
模块中的子程序和函数默认是全局可用的,所以在模块1中可以直接调用,如下面的代码。
VBA |
Sub test() Debug.Print (isLeap(2000)) End Sub |
执行代码会显示True,可以修改IsLeap()函数的参数来观察执行结果。
此外,整数也可以进行布尔运算,如使用Or运算符可以很方便的组合状态码,假如有如下状态代码:
大家可以看到,除了0,其它状态码是2的0次方到2次方,这一点很关键,即需要使用2的次方数表示状态码。如果使用一个变量表示同时拥有状态A和状态C,可以使用“1 Or 4”组合状态码,如下面的代码。
VBA |
Sub test() Dim state As Integer state = 1 Or 4 Debug.Print (state) End Sub |
执行代码会显示5。判断一个变量的值是否包含状态C时可以使用“state And 4”,如下面的代码。
VBA |
Sub test() Dim state As Integer state = 1 Or 4 Debug.Print (state And 4) End Sub |
执行代码会显示4,即包含状态码4。这里可修改“state And 4”中的4来观察执行结果。
实际应用中,往往会使用常量表示各种状态,并可以直接使用常量进行运算和判断,如下面的代码。
VBA |
Const uNoState = 0 Const uStateA = 1 Const uStateB = 2 Const uStateC = 4 Sub test() Dim state As Integer state = uStateA Or uStateC Debug.Print ((state And uStateC) = uStateC) End Sub |
执行代码会显示True,即state变量中包含了状态uStateC。
VBA中的整数的布尔运算实际执行的是整数的位运算,有兴趣可以深入了解。
比较条件
VBA中基本的比较条件包括:
等于,使用=运算符,判断两个运算数是否相等。请注意,VBA代码中等于运算符和赋值运算符都使用等号(=),运行时会根据语义自动判断其功能。
不等于,使用<>运算符,如a<>b中,a不等于b返回True,否则返回False。
大于,使用>运算符,如a>b中,a大于b返回True,否则返回False。
大于等于,使用>=运算符,如a>=b中,a大于或等于b时返回True,否则返回False。
小于,使用<运算符,如a<b中,a小于b时返回True,否则返回False。
小于等于,使用<=运算符,如a<=b中,a小于等于b时返回True,否则返回False。
接下来在条件语句中演示比较条件的应用。
条件语句(If...Then...End If)
条件语句的应用是比较灵活的,先来看一个简单的条件语句结构,如下面的代码。
VBA |
If <条件> Then ' 语句1 End If |
此结构中,当<条件>判断成立(True)时会执行语句1处的代码,然后执行End If语句后的代码;<条件>判断不成立(False)时会直接执行End If语句后的代码。如下面的代码,当年份是闰年时会显示提示信息。
VBA |
Sub test() Dim year As Integer year = 2000 If isLeap(year) Then Debug.Print (year & "年是闰年") End If End Sub |
执行代码会显示“2000年是闰年”,可以修改year变量的值来观察执行结果。实际上,如果条件成立时执行的代码只有一行,也可以将此行代码写在Then关键字后面,同时省略End If语句,如上述代码可以改写为如下代码。
VBA |
Sub test() Dim year As Integer year = 2000 If isLeap(year) Then Debug.Print (year & "年是闰年") End Sub |
在If语句结构中还可以添加Else语句来处理条件不成立时的情况,如下面的代码。
VBA |
Sub test() Dim year As Integer year = 2001 If isLeap(year) Then Debug.Print (year & "年是闰年") Else Debug.Print (year & "年不是闰年") End If End Sub |
执行代码会显示“2001年不是闰年”,可以修改year变量的值来观察执行结果。
需要处理多个条件时,可以添加ElseIf语句部分,如下面的结构。
VBA |
If <条件1> Then ' 语句1 ElseIf <条件2> Then ' 语句2 '... ElseIf <条件n> Then ' 语句n Else ' 语句n+1 End If |
在此语句结构中,可以有一个或多个ElseIf语句结构,执行逻辑为:当<条件1>成立时执行“语句1”,否则当<条件2>成立时执行“语句2”,否则当<条件n>成立时执行“语句n”,当所有条件都不成立时执行“语句n+1”。
下面的代码演示了If语句处理多条件的情况。
VBA |
Sub test() Dim color As String, result As String color = "red" result = "" If color = "red" Then result = "红" ElseIf color = "green" Then result = "绿" ElseIf color = "blue" Then result = "蓝" End If Debug.Print (result) End Sub |
代码中将变量result初始值设置为空字符串(空白文本),然后根据color的内容显示中文颜色,这里没有使用Else语句部分,当输入的不是red、green或blue时会显示为空白。
选择语句(Select Case)
Select Case语句结构同样是根据条件分别执行不同的语句,与If语句结构不同的是,If语句会根据不同的条件是否成立分别执行对应的代码,而Select Case语句的条件只有一个,会根据表达式的不同的值分别执行对应的代码,其应用结构如下。
VBA |
Select Case <表达式> Case 值1 ' 语句1 Case 值2 ' 语句2 Case 值n ' 语句n Case Else ' 语句n+1 End Select |
在此结构中,会根据<表达式>的值分别执行对应的语句,对于<表达式>的值,如所有Case语句都没有对应的值,而执行Case Else语句部分。这里,Case Else语句部分是可选的。
使用Case语句指定对应的数据时,其形式也比较灵活,可以列一个值,可以使用逗号分隔列出多个值,也可以使用To关键字指定数据区间,或使用Is关键字指定比较条件。下面的代码,我们使用Select Case语句结构获取指定年份和月份的天数。
VBA |
Sub test() Dim year As Integer, month As Integer year = 2000 month = 2 daysInMonth = -1 ' Select Case month Case 1, 3, 5, 7, 8, 10, 12 daysInMonth = 31 Case 4, 6, 9, 11 daysInMonth = 30 Case 2 If isLeap(year) Then daysInMonth = 29 Else daysInMonth = 28 End If End Select ' Debug.Print (year & "年" & month & "月有" & daysInMonth & "天") End Sub |
执行代码会显示“2000年2月有29天”,可以修改变量year和month的值来观察执行结果。代码中会根据month变量的值分别执行对应的代码,当月份为1、3、5、7、8、10、12时天数为31,当月份为4、6、9、11时天数为30天,当月份为2时,闰年为29天,不是闰年为28天。本例,在选择语句结构前先指定了daysInMonth变量的默认值为-1,如果指定的月份不是1到12时,显示天数为-1;这样可以省略Select Case语句结构中的Case Else语句部分;此外,当某个月的天数是-1时显然是有问题的,此时就要检查代码和数据。
下面的代码演示了Case语句中如何使用To和Is关键字指定数据的范围。
VBA |
Sub test() Dim n As Integer, result As String n = 1 result = "" ' Select Case n Case 0 To 9 result = "一位整数" Case 10 To 99 result = "两位整数" Case Is >= 100 result = "三位以上整数" End Select ' Debug.Print (result) End Sub |
执行代码会显示“一位整数”,可以修改变量n的值来观察执行结果。