购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.3 逻辑表达式
——怎样表示“与”“或”“非”

4.3.1 逻辑表达式

使用嵌套的判断结构可以依据多个条件进行综合判断,比如案例4-3中根据平均成绩与数学成绩两个条件决定奖学金数额。不过在日常生活中,我们也会经常采用另外一种表达方式来描述这种规则,例如:

如果平均成绩达到80分并且数学成绩达到90分,则发放奖学金3000元;

否则,如果平均成绩达到80分并且数学成绩低于90分,则发放奖学金2000元;

否则,如果不符合上述任何一个条件,则不发放奖学金。

在这种表述形式中,每句判断规则都能够兼顾“平均成绩”与“数学成绩”两个因素,原因就在于它使用了“并且”这个表示逻辑关系的连词。类似的,人类语言中还会经常用到“或者”和“并非”两个连词,也就是逻辑学中的基础概念“与”“或”“非”。通过搭配使用这三个连词,可以将多个判断条件组合在一起,从而表达非常复杂的判断规则。因此 VBA 等程序设计语言也专门定义了一些逻辑运算符来表示这些逻辑关系,其中最常用的就是“And(与)”“Or(或)”和“Not(非)”。

使用这些关键字将多个条件拼合在一起,就构成一个逻辑表达式,比如“平均成绩 >=80 And 数学成绩 >=90”。本节就介绍一下怎样在If结构中使用这些逻辑表达式。

4.3.2 常见逻辑运算符的使用方法

1.使用“And”表示“并且”

使用“And”将两个条件连接在一起时,只有两个条件都成立,才被认为符合整个判断条件,从而允许执行Then后面的分支。例如案例4-3也可以使用下面的代码来实现:

读者可能会觉得这段代码并不比之前使用嵌套If结构书写的代码简单。没错,这是因为在案例4-3中,对于“平均成绩达到80分”和“数学成绩达到90分”这两个判断条件,我们必须既考虑其成立时的情况(比如数学成绩达到90分则发放奖学金3000元),又考虑其不成立时的情况(比如平均成绩小于80分则发放奖学金0元)。换言之,程序中存在很多Else分支。在这种情况下,使用嵌套循环往往能够更清晰地表现层层递进的结构。

但是当不需要为每个判断条件都书写Else分支时,使用嵌套结构就会让代码显得非常繁杂,例如遇到案例4-4的情况。

案例4-4: 重新修订案例4-2的奖学金发放规则,只有平均成绩在80分及以上,并且每科成绩都在60分以上的同学才有资格获得奖学金,金额一律为1000元。案例4-4的原始数据及预期运行效果如图4.18所示。

图4.18 案例4-4的原始数据及预期运行效果

对于修改后的规则,如果使用嵌套的判断结构就需要书写4层If语句,形如下面的代码:

这种形如箭头般的嵌套结构很容易让人联想起《龙珠》等动漫中经常出现的气功波,可以说是很多程序员的噩梦之一。事实上,我们已经使用了用默认值代替Else语句的技巧来简化这段代码,否则还需要为每个If语句添加一句“Else Cells(i,7)=0”,代码将变得更加复杂(请读者思考一下:为什么需要为每个If语句都添加一个Else语句?)。

但是通过使用多个And运算符,将所有条件连接成一个逻辑表达式,只需书写一个If结构就能实现案例4-4的要求,阅读起来也很容易理解。

2.使用“Or”表示“或者”

使用“Or”将两个条件连接在一起时,只要其中一个条件成立,无论另一个条件是否成立,都会认为符合整个判断条件,并执行Then后面的分支内容。例如案例4-5中再次修订的获得奖学金的规则。

案例4-5: 现将获得奖学金的规则改为“单科优秀成绩奖”,即只要有一门课程的成绩达到90分,就给予3000元奖学金,不必考虑平均成绩。若某些同学有多门课程的成绩达到90分,也只发放3000元奖学金。案例4-5的原始数据及预期运行效果如图4.19所示。

图4.19 案例4-5的原始数据及预期运行效果

把“只要有一门课程的成绩达到90分”这句话细化一下,也就是“语文成绩达到90分,或者数学成绩达到90分,或者英语成绩达到90分”,显然可以用“Or”关键字直接表示为VBA语句,写成下面的代码:

这段代码中只使用了一个If结构,但是其中包含了三个由Or连接起来的判断条件,只要三个条件中有一个条件成立就执行“Cells(i,7)=3000”这个语句。只有当三个条件都无法满足(也就是所有科目的成绩都少于90分)时,才会执行“Cells(i,7)=0”语句。这就是“或者”的含义。

就像使用含有Else语句的If结构可以不使用And一样,不使用Or也能够表达这种“或者”关系,只不过需要用到多个If语句:

上面这段代码包含三个互相独立的If语句,每次循环到一行时都会把这三个If语句依次执行一遍。一旦执行某个If语句时发现符合条件,就会将G列单元格的数值由0修改为3000。为了简化书写,这里既使用了默认值技巧,也使用了单行If语句的写法。显然,它的运行效果与使用Or是一样的。

3.逻辑运算的优先级

将And与Or等逻辑运算符组合使用,可以表示各种复杂的判断条件。与算术运算中“先乘除,后加减”的优先级规则一样,不同的逻辑运算符之间也存在优先级问题,在混合使用时必须格外注意。比如遇到案例4-6中的情况。

案例4-6: 再次修订获得奖学金的规则:平均成绩达到80分,并且语文成绩达到90分或者数学成绩达到85分,则可获得3000元奖学金,其他情况无奖学金。案例4-6的原始数据及预期运行效果如图4.20所示。

图4.20 案例4-6的原始数据及预期运行效果

对于这个计算规则,如果只是像下面的代码一样简单地将“并且”写成“And”,将“或者”写成“Or”,那么运行结果将发生错误,会为第7行的田七也发放3000元奖学金,如图4.21所示。

图4.21 未考虑优先级的程序及其运行效果(右下角)

之所以会出现这种错误,是因为当And与Or同时出现时,VBA会优先合并And两端的判断条件。换言之,And的优先级高于Or。所以这段代码中的If语句在执行中被分解为下面两部分:

① 第6列的数值(平均分)大于等于80并且第3列的数值(语文成绩)大于90。

② 第4列的数值(数学成绩)大于等于85。

由于①与②之间是“或者”关系,所以只要某个学生的成绩满足上面任何一个条件都被认为符合判断规则,并将其G列的值设置为3000。因此,虽然第7行“田七”的平均分只有67分,不满足条件①,但是其数学成绩达到了88分,完全满足条件②,所以这个程序也在“田七”的G列中写入了数字3000。

为了避免这种由于默认优先级导致的错误,VBA允许使用圆括号改变逻辑运算的优先级,就像在算术运算中使用圆括号实现“先算加减,后算乘除”一样。因此案例4-6的正确代码写法如下:

因为使用了圆括号,所以这次 VBA 会优先合并圆括号中的条件,再考虑其他条件。也就是说,这段代码中的判断条件被分解为下面两部分:

① 第6列的数值(平均分)大于等于80。

② 第3列的数值(语文成绩)大于等于90或者第4列的数值(数学成绩)大于等于85。

由于两者之间是“And”关系,所以只有同时满足这两部分才被认为符合判断条件。

因为很多错误都是由忽视逻辑运算优先级导致的,所以建议读者在编写复杂逻辑关系式时,尽量使用圆括号明确指定运算顺序。

4.使用“Not”表示“并非”

“Not”意为“并非”或“否定”。例如“If Not(a>5)Then …”,意即“如果a并非大于5则……”,相当于“If a<=5 Then …”。灵活使用Not运算符更利于我们思考,比如案例4-7。

案例4-7: 图4.22左图所示为已经计算出的基本奖学金发放表。但是在正式执行之前,学校决定在该表格数据的基础上再补发一批奖学金。相关文件对补发规则的描述为:“原则上所有同学均补发500元奖学金,但存在以下情形者不予补发,而是维持原定金额:语文或数学成绩不及格,同时平均分低于60分”,预期运行效果如图4.22右图所示。

图4.22 案例4-7的原始数据及预期运行效果

这个案例的特殊之处在于,文件是从“否定”的角度描述计算规则的,即文件中没有说在什么情况下应当重新计算奖学金,而是在什么情况下不重新计算。所以很多初学者在遇到这类“反向”问题时往往会编写出类似下面的代码:

这段代码执行起来没有任何问题,但是If结构的第一个分支(Then与Else之间)完全没有执行任何操作,因此这种写法实质上是在用一个双分支结构表述一个单分支问题。虽然运行结果正确,但是多出来的空白分支还是会给阅读和修改程序带来隐患。

当然,我们可以找出所有反例,对规则进行“逆向”描述,比如下面的代码:

这段代码中的判断条件含义为“如果语文和数学成绩都及格,或者平均分达到60分,则增发500元奖学金”。仔细想一下会发现,它其实就是案例4-7中规则的“逆向”表述,所以运行结果同样正确,而且只使用了一个判断分支。

只不过对于初学逻辑表达式的读者来说,往往很难把一个规则快速、准确地翻译成逆向表达形式。案例4-7属于非常简单的规则,思考起来尚且需要一点时间,而对于类似 “如果数学成绩低于60分并且语文成绩低于70分,或者英语成绩低于60分并且数学成绩和语文成绩中有一科低于70分,或者平均分低于60分并且某一科成绩也低于60分者,不予发放奖学金” 这样的规则,恐怕即使专业开发人员也需要运用看上去颇具反人类色彩的“布尔代数”进行推导。

但是使用Not运算符之后,这个问题就会变得十分简单:我们可以先按照文件中的规则编写逻辑表达式,即在何种情况下不发奖学金,然后只需在前面加上一个“Not”,就可以表达出“反之”的含义,也就是何种情况不属于不发奖学金,即应当发放奖学金。写成代码形式如下:

在这段代码的If语句中,位于Not括号内的逻辑表达式就是对案例4-7中的文字(“语文或数学成绩不及格,同时平均分低于60分”)的直接翻译,但是由于加上了 Not,整个判断条件的含义就正好相反。

需要注意的是,当Not、And和Or同时出现在一个逻辑表达式中时,Not的运算优先级最高,其次为And,最后为Or。所以如果删除这段代码中最外面的一层括号,也就是让判断条件变为如下形式,那么它的含义就会变成“对于语文和数学成绩都及格,同时平均分小于60分者,发放奖学金”,导致运行错误。

5.初学者陷阱——逻辑表达式必须书写完整

使用逻辑表达式时,初学者往往会习惯性地按照数学课本中的格式书写 VBA 代码,结果导致程序出错。比如,在表达“如果a大于3并小于5,则……”时,正确的写法应该是:“If a >3 And a < 5 Then”,但很多初学者会把它写成“If 3 < a < 5 Then”。这种写法虽然让人很容易理解,但是从计算机的角度来看,其含义却完全不同。因为这个判断是由“a大于3”和“a小于5”两个条件构成,而且它们之间是“并且”的关系,所以只有写成“If a > 3 And a < 5 Then”的形式才能被计算机正确识读。

同样的道理,若想表达“如果 a 等于 b 并等于 c”,也不能写成“If a=b=c Then”的格式,而是要将这个逻辑关系的每个部分都完整地写出来,即“If a=b And a=c Then”的格式。

不过即使写成“If 3 < a < 5 Then”或者“If a=b=c Then”的格式,VBA程序也能够正常执行,不会提示任何错误。只不过由于这些代码的含义与我们的判断规则完全无关,所以运行的结果很可能发生严重的错误。至于为什么这些错误写法仍然能够正常执行,待讲解完数据类型中逻辑变量的知识后,读者就可以结合赋值语句的执行流程思考清楚。 JgREWR287tJy8+ujwIVzjEvMitaIUg9qbofS761qVgY8Q2WOodbsGN7sRVsvtudE

点击中间区域
呼出菜单
上一章
目录
下一章
×