之 循环语句
循环语句,顾名思义,就是让某一段语句反复运行,直到满足了某个条件时,才终止这段语句的运行,循环语句是各种编程语言中不可或缺的语句,它不但能简化程序语言,有时不用循环语句,就无法完成某些工作。在编程语言的编写过程中,它和判断语句一样重要,只有懂得了它的精髓,我们才能让计算机像我们的佣人一样为我们服务,我觉得驾驭计算机,其实是一种乐趣。
一.DO….LOOP循环语句
1. do …… loop 循环语句
格式:do
执行语句>
执行语句]
……
逻辑表达式 then Exit do >
Loop
例:dim a%
Do
A=a+1
If a>10 then exit do
Loop
Msgbox “现在变量a的值是:” & a
在这个例子里,dim语句和msgbox语句不是循环语句里的,dim语句是定义了一个变量a,msgbox是在循环完成后,弹出个窗口显示循环完成后a的值。
Do 是循环的开头,loop 是循环的结尾,do 和 loop 之间是需要执行的循环语句,中间的if判断语句为当条件为真时,退出循环。在这种循环语句中,循环之初do并不给退出循环的条件,所以循环中间的通过判断语句退出循环必不可少,缺少了判断语句,那就是一个失败的循环,即死循环。在这个循环之中的判断语句,并不一定固定是if…end if这种,它可以是那六种判断语句里的任何一种,但必须得有可行的条件,如果条件不可能实现,就算有判断语句也只能算是失败的循环。如在这个例子中的条件为a<0,就不行。
在这个循环一开始,我并没有对变量a进行赋值,它在未赋值的情况下,默认值是0。第一次循环,a=a+1,运行这句后变量a的值就变成了1,然后执行判断语句,这时a的值不符合条件a>10,执行到loop后,程序会自动将运行顺序调到do处,接着执行do下面的语句,直到a的值为11时,条件a>10为真,才会退出循环。
有时我们执行循环后,需要得到变量的值,执行语句的顺序不一样,得到的值就不一样,同样是这个例子中
Do
A=a+1
If a>10 then exit do
Loop
和
Do
If a>10 then exit do
A=a+1
Loop
循环结束后,变量a的值是不一样的,想一想 为什么?
现在你也许会问,这样的程序有什么用呢?现在我来举个实用的例子:假设现在已打开一个工作簿,当前活动区域为工作表1,内容如下图
A | B | C | |
1 | 姓名 | 成绩 | |
2 | A1 | 90 | |
3 | A2 | 54 | |
4 | A3 | 66 | |
5 | A4 | 87 | |
6 | A5 | 98 |
Sub aa()
Dim a%
A=1
Do
A=a+1
If a > 6 then
Exit do
Else
If cells(a,2) >80 and cells(a,2) <= 90 then cells(a,3)=”良”
End if
Loop
End sub
建一个上面的工作表,运行以上代码,分析每一句运行的作用及含义,自己换一种条件再试,直到理解代码的含义为止。
2. DO WHILE …..LOOP循环语句
格式:do while <逻辑表达式>
执行语句>
执行语句]
……
Loop
这个循环语句比上面的那个循环语句多了个逻辑表达式,这个逻辑表达式的值就是退出循环的判断,当这个逻辑表达式的值为真时循环,为假时就退出循环。用这个循环语句就可以省去上面那个循环语句中的退出循环判断语句,达到简化程序的作用。
这个循环语句只是比上面的那个循环多了个WHILE<逻辑表达式>,运行的原理还是和上面的循环语句一样的,同样是DO是循环的开头,每循环一次都从DO下面的语句开始,最后以LOOP结束,直到退出循环。
同样是上面的工作表,我们用这个DO WHILE…..LOOP语句再做一次:
A | B | C | |
1 | 姓名 | 成绩 | |
2 | A1 | 90 | |
3 | A2 | 54 | |
4 | A3 | 66 | |
5 | A4 | 87 | |
6 | A5 | 98 |
Sub aa()
Dim a%
A=2
Do while cells(a,2) <>””
If cells(a,2) > 80 and cells(a,2) <= 90 then cells(a,3) =”良”
A=a+1
Loop
End sub
这样写是不是要比上面的那种循环要简化一些?
3. DO UNTIL…..LOOP循环语句
格式:do until <逻辑表达式>
执行语句>
执行语句]
……
Loop
这个循环语句和第二个循环语句的用法是一样的,只不过第二个循环语句的逻辑表达式为真时执行循环里的执行语句,而这个刚好相反,当这个语句的逻辑表达式的值为真时,退出循环。怎么样?是不是觉得很神奇,或者也可以说是无聊。不过存在就有意义,有时就会有用到它的时候,只不过你还没有发现。
如果用这个循环语句再做一次上面的作业,其实就是把逻辑表达式的运算符换一下而已:
Sub aa()
Dim a%
A=2
Do until cells(a,2) = ””
If cells(a,2) > 80 and cells(a,2) <= 90 then cells(a,3) =”良”
A=a+1
Loop
End sub
趣味小例-隔行填色
Sub aa()
Dim a%
A=2
Do until sheet1.range(“a” & a) = “”
Range.range(“a” & a & ”:g” & a).interior.colorindex=7
A=a+1
Loop
End sub
这段程序里,interior为这个单元格的底,color是颜色的意思,index为设置成,7是颜色的代码,这里7是紫色,这段意思是将选定的区域底色设置成紫色。
小结:以上三种循环语句,称为DO….LOOP循环语句,实事上,VBA的编写具有很大的灵活性,如第二种循环里的while<逻辑表达式>和第三种循环语句里的until<逻辑表达式>,不仅可以放在DO的后面,它还可以放在LOOP的后面。例:
Sub aa()
Dim a$
Do
A = inputbox(“请输入密码:”)
Loop until a=”123”
End sub
上面这段代码运行后,会弹出一个可输入数据的对话框,你只有在对话框里输入了”123”(引号不用输入),才会退出循环,那么until放在DO后和放在LOOP有什么区别呢?它的区别在于放在LOOP后的循环次次要比放在DO后少循环一次。这里如果把until换成while会怎么样呢?意思刚好相反,只有输入”123”才循环,输入错误就退出循环。
如果在运行后,而你忘了或不知道密码是多少,这又会成了死循环,我们还可以一下次数:
Sub aa()
Dim a$ b!
Do
B=b+1
If b > 3 then exit do
A = inputbox(“请输入密码(最多输入三次):”)
Loop until a=”123”
End sub
从上面这些就可以看出,其实上面三种循环语句其实可以统称为DO…..LOOP循环语句,它的完整格式是这样的:
Do [{while | until}<逻辑表达式>]
<执行语句>
[执行语句]
[exit do ]
[执行语句]
Loop
或者:
Do<执行语句>
[执行语句]
[exit do ]
[执行语句]
Loop [{while | until}<逻辑表达式>]
注:1.用while时,逻辑表达式为真就循环,用until时,逻辑表达式为真时退出循环。
或until即可以放在DO的后面,也可以放在LOOP的后面,区别在于放在DO的后面是先判断再循环,而放在LOOP的后面是先循环再判断。
DO….LOOP通常和判断语句 + EXIT DO结合使用,在一个循环里面还可以放置多个判断语句 + EXIT DO以便能随时退出循环。
的意思是退出循环。但它只能退出所在循环内的循环,在以后还会用到多层循环套用,在那种情况下,如果执行到exit do,程序只能退出它所在的循环,再次进入到离它最近的外循环里去。
如果出现死循环,可以按ctrl+break组合键来结束运行。
二.FOR…..NEXT循环语句
1.For each…….next循环语句
格式:for each <对象> in <集合>
执行语句>
执行语句]
…..
Next
这个循环语句,同样需要有条件才能退出,但却没有用到逻辑表达式,在这个循环语句里的循环条件就是<集合>里的所有<对象>,从第一个对象开始,循环一遍后再指向下一个对象,直到最后个对象执行完成后,退出循环。例:
A | B | C | |
1 | 姓名 | 成绩 | |
2 | A1 | 90 | |
3 | A2 | 54 | |
4 | A1 | 66 | |
5 | A1 | 87 | |
6 | A5 | 98 |
Sub aa()
Dim a as range
For each a in sheet1.range(“a2:a6”)
If a = “A1” then a.interior.colorindex = 3
Next
End sub
在这个程序里,我来逐句解释一下
1.首先我们定义了一个对象a,range是对象型数据,不同于以前的数据类型,在这里也可以把它理解为把变量a定义成一个单元格型数据。
2.在第二句里,a就是这个语句里的<对象>,sheet1.range(“a2:a6”)是一个集合,在这里它代表一个区域,就是指从A1到A6的这块单元格区域,循环的条件就是从A列的第一个单元格到A列的第六个单元格。这里也可以理解为在从A1到A6这个区域里取出每个单元格,直到取完为止,也就是说这个区域里有多少个单元格就循环多少次。
3.循环里只有一个判断,只有当这个单元格的内容为”A1”时才会将当前的活动单元格变成红色。3是红色的代码,interior指的是这个单元格的底,即背景色,interior.colorindex合在起就是设置背景色颜色的意思,前面加上a.就是指设置变量a所指的单元格背景色,整句if的意思就是,如果(if)当前变量a所指的单元格内容为”A1”(a=”A1”)那么(then),它所在的单元格背景色赋值为红色a.interior.colorindex = 3。
4.经过next后,程序又将指针指向for处,每执行一次循环,当前的活动单元格就会指向集合中的下一个单元格,直到所有对象操作完,退出循环。
For each…enxt循环语句对于初学者,会感觉像和以前的思维不一样了,有点难以理解,下面我再举个例子,看的多了也就能想通了。
下面这个例子是把当前打开工作簿内的工作表名依次输入到第一个表的第三列,从第一个单元格开始,一个单元格显示一个工作表名,有几个工作表显示几行。
sub aa()
Dim a as worksheet,n as byte
For each a in worksheets
N=n+1
Sheet1.cells(n,3) = a.name
Next
End sub
下面我再逐步解释一下:
1.第一行还是定义变量,这次把a定义成了一个工作表型数据。用dim定义变量,可以一次定义多个变量,各个变量之间须用逗号分开。
2.第二行循环开始,循环的条件是从在当前的工作表集合中逐个对对象a(现在它是个工作表)进行操作。第一次循环时它就是第一个工作表,如果是新建的工作簿,它就是sheet1,第二次循环时,它就是sheet2,直到所有的工作表操作完,退出循环。
3.第三句中的n,用dim定义后,我们并没有为它赋值,在执行这句之前,n的默认值是0,执行这句后变量n就成了1,在下句Sheet1.cells(n,3)中引用这个变量时,n就代表行数。有了这个变量,我们就能在逐个将工作表名分别赋值到相对应的单元格内,如果没有这个变量,我们就只能在指定的固定单元格赋值,程序运行到最后,这个单元格内显示的也只是最后一个工作表名。 在定义这个变量时,我们用了byte这个单字节类型。但不要望文生义,这个单字节并不是只能占一个字节,并不是只能在0-9之内,一个字节在内存中占的是一个八位的二进制单位,这个单字节实际上的范围是0-255。
4.第四句是个赋值的语句,Sheet1.cells(n,3) = a.name语句中:= 前面的的意思是第一个工作表(sheet1)内第n行,第3列单元格(cells(n,3)),sheet和cells之间用”.”来连接,= 后面是a工作表名字(a.name)在这里如果是a的后面没有加上”.name”,运行后就会出现“应用程序定义或对象定义错误“的提示,这是因为我们定义的变量a是一个工作表类型的数据,它不像字符型或数据型等可以显示在单元格内,在加上了”.name”之后,那么就是这个工作表的名字,名字是可以显示在单元格内的。理解这一点可以有点难度,但真正理解之后,就能达到“山穷水穷疑无路,柳暗花明又一村”的境界。
5.next 将运行指针返回到for each处,如果还有工作表,就执行再执行循环的内容,直到不再有工作表了。
2. for…..next循环语句
格式:for <数值型赋值> to <数值型变量或常量> [step <步长>]
执行语句>
执行语句]
……
Next
注:1. 在for 后必须是一个变量的数值型赋值,如a=1,这里的变量就是一个对象,它必须是一个数值。
2.在to后则必须是一个数值型数据,可以是常量,也可以是变量。它其实就是一个数值集,一个能从to前变量值到这个数值之间的数值集。
3.for….next与do…loop最大的区别在于,for…next循环语句有个内置的计数器step,在缺省的情况下step默认为是step 1,意思是每循环一次,for后面的变量值+1,如果是step 2,就是每循环一次,for后面的变量值是+2,这个步进不仅可以累加,也可以累减,如果是step -1,那每循环一次,for后面的变量值就会-1,用setp一定要注意,这个步进一定要能从for后的变量值能to后数值的步进。不然又会成为死循环。
举例:1到100的累加,以对话框的形式显示出来。
Sub aa()
Dim a!,b!
For a=1 to 100
B=b+a
Next
Msgbox b
End sub
在这段程序中,第三句for后面的a就相当于一个对象,a=1,就是要让变量a为1时开始循环,to后面的100就是一个数值集,这个集的内容就是1-100,由于这个程序的步进是累加所有集是1-100,如果是for a=100 to 1 step -1,那这个集就是100-1了。这个集也只是在这一行适用,如果是写成for a=1 to 100 step -1,步进就变成了累减,由于给a赋的值是集的开始,to后是集的结束,step -1会超出集1-100的范围,这时系统不会报错,只是不执行循环,而直接执行next后面的语句。过了这一句,这个集就只认不大于100,而不认不小于1了,即使a的值为-100,也不会退出循环,也就是说如果这个步进是1→100,只有当a值大于100时才退出循环,而不管是不是小于1,如果这个步进是100→1,就只有当a值小于1时才退出循环,而不管是不是大于100。亲,懂?
这段程度就是计算1-100的累加和,相当于1+2+3+…..+100=? ,其中变量a是需要累加的数,第一次循环为1,第二次循环是2,第100次是100,超过100退出循环,变量b为每次累加的和,循环之初为0,第一次循环a是1,和就是1,第二次循环时,a是2,和就是上次的和加上这次的2,直到a是100,退出循环,以窗口的形式(msgbox b)显示出累加的值。
如果是1-100内的奇数累加,我们就可以写成这样:
Sub aa()
Dim a!,b!
For a=1 to 100 step 2
B=b+a
Next
Msgbox b
End sub
步进数是2,也就是说每循环一次,a=a+2,第一次循环是1第二次循环是3,最后一次循环是99,再然后是101就超出集的范围,不再累加面退出循环。
如果是1-100内的偶数累加只需要赋值时,将a赋值为2就可以
在这里如果用累减的步进也是一样的,只不过如果是奇数累加将For a=1 to 100 step 2写成for a=99 to 1 step -2,如果是偶数累加则写成for a=100 to 1 step -2,注意循环的起点值也很重要。
下面讲一个实用的循环实例:
A | B | C | D | |
1 | 货名 | 单价(元) | 数量 | 金额 |
2 | A1 | 90 | 6 | |
3 | A2 | 54 | 10 | |
4 | A3 | 66 | 23 | |
5 | A4 | 87 | 8 | |
6 | A5 | 98 | 12 |
Sub aa()
a = Sheets(1).[A65536].End(xlUp).Row
for b=2 to a
next
end sub
逐句分析:
1.这里我们用到一个新语句Sheets(1).[A65536].End(xlUp).Row,这里我们可以理解为:第一个工作表(Sheets(1))里A列所有区域里([A65536])从最后一行向上(End(xlUp))第一个非空单元格所在的行号,在这一句里就是把这个行号值赋于变量a,这句以后会经常用到。
2.循环的范围是从第二行开始,到A列的最后一个非空单元格。
3.在第一个工作表sheet1,第b行第4列cells(b,4)赋值为:第b行第2列的数据与第b行第3列的数据的积clees(b,2)*clees(b,3)。
4.循环至所有A列非空单元格。
小节:
以上两种循环语句称为:FOR…..NEXT循环语句。这种FOR循环,我们也可以理解为,对象在集合中的依次出现的循环,只不过第一种FOR是非数值型的对象与集合,第二种FOR是数值型的对象与集合。
在DO循环里有一种随时退出循环的命令EXIT DO,在FOR循环里也有一种随时退出循环的命令:EXIT FOR。
第一种FOR循环比较抽象,不容易理解,我们经常用到的是第二种FOR循环。
三.多层循环(循环的嵌套使用)
在循环的嵌套使用中,应注意内循环完全在外循环之内,不可以交错使用。
多层循环可以是双层循环,也可以是多层循环,只要你需要用到,就可以一直嵌套下去,直到满意为止。
它可以是DO…LOOP套DO….LOOP,FOR…NEXT套FOR…NEST,也可以是DO…LOOP套FOR…NEXT,FOR…NEXT套DO…LOOP。
循环里用到的退出循环有三个:EXIT DO,EXIT FOR,EXIT SUB。EXIT DO是退出离它最近的DO循环,EXIT FOR是退出离它最近的FOR循环,EXIT SUB是直接退出宏运行。
虽然多层循环时,循环不可以交错使用,但在设计时却提供了能直接退出到它的上上级循环处。甚至直接退出宏运行。例:
Sub aa()
Aa=0
For a=1 to 10
Aa=aa+1
B=1
Do
B=b+1
If b>5 then exit for
Loop
Next
Msgbox “外层循环共循环了” & aa & “遍”
End sub
在这个循环里,就用到了双层循环,并且是FOR循环套DO循环。并且在内循环DO语句里用到了EXIT FOR。,下面逐步讲解一下:
1.为aa变量赋值为0,这个变量会出现在外层循环里,用它的意思是让它来代表外循环的次数。为什么不能用外循环里的变量a来表示外循环的次数呢?因为外循环FOR…NEXT每完整的循环一次,循环的次数就是a-1,而内循环里用了EXIT FOR,第一次循环是执行了一次,但没有完整的执行就直接跳到外循环NEXT下面的一句,外循环的次数就是a。而用aa来代表循环的次数就没有这个情况,FOR循环了几次,aa就累加几数,aa就是循环的次数。
2.设置外循环的条件是变量a的值从1到10,我们预设外循环共十次。
3.aa=aa+1在第1条里讲了,只是计算外循环累加的次数,不再敖述。
4.设置b变量只是为了让内循环有个退出的条件。没有其它的意思
5.内循环开始
6.为内循环退出制造条件,让变量b累加。
7.这里用了个单行的判断语句。让变量b>5时退出,而且是退出最近的FOR循环,去执行最近的FOR循环LOOP下面的语句。
8.为DO循环结束。不管这句在程序运行中有没有执行到,我们必须为DO循环设置个结束。
9.为FOR循环结束。在这里可以看出DO…LOOP完全在FOR…NEXT之内,如果将LOOP和NEXT换下位置,就会提示错误。
10.以窗口的形式显示外循环的次数。
运行这段代码之后就会看到弹出个窗口:外层循环共循环了1遍,这是因为在b值6时执行了EXIT FOR,就直接执行MSGBOX语句了。这时你也许会问,这个EXIT FOR是不是退出所有的FOR循环呢?那我们再用个FOR循环,来个三层嵌套循环:
Sub aa()
Dim aa!,cc!
For c=1 to 10
Cc=cc+1
For a=1 to 10
Aa=aa+1
B=1
Do
B=b+1
If b>5 then exit for
Loop
Next
Next
Msgbox “外循环” & cc & “遍,中循环” & aa & “遍”
End sub
这段代码执行后,就看到提示:外循环10遍,中循环10遍。这里的意思是外循环每循环一次,中循环也只跟着循环了一次,EXIT FOR退出的只是最它最近的那个NEXT。如果内层循环里用的是EXIT DO,就会提示:外循环10遍,中循环100遍。
这时有细心的朋友可能就会问了,你怎么写代码不是左对齐呀?其实这不是个性,也不是为了花哨。而是有规则的:在写代码时,特别是多层循环第一层循环的开关在纵向上要与结尾对齐,第二层循环要比第一层循环向右一部分。并且开关与结尾也要纵向对齐,依次类推。这样写的好处在于能够让代码清晰易懂,不容易出错。如果你非要左对齐也没有关系,没办法,脑子好,任性。