Excel VBA 程式設計教學:迴圈控制,For Loop、For Each 與 Do Loop

本篇介紹 Excel VBA 的迴圈使用方式,並提供實用的範例程式碼。

迴圈控制是各種程式語言都會有的基本功能,他的作用是可以讓電腦重複執行某一段類似的動作,在運用得當的情況下,可以幫助使用者快速處理大料的資料,既省時又省力。


在 Excel VBA 中的迴圈主要可分為 For LoopFor EachDo Loop 這幾種,不同的迴圈適用於不同類型的問題,以下是各種 VBA 迴圈的語法教學。

For Loop 迴圈

For Loop 迴圈主要用於已知重複次數的問題,也就是在執行迴圈之前,就已經事先知道要迭代幾次。

For 迭代變數 = 開始值 To 結束值
運算內容
Next 迭代變數

For Loop 迴圈執行時,迭代變數會從開始值不斷遞增至結束值,每次遞增時都會執行一次運算內容。以下是一個計算從 110 總和的範例:

Dim i, s As Integer
s = 0
For i = 1 To 10
  s = s + i
Next i
MsgBox "s = " & s

以這個例子來說 i 就是迭代變數,在 For Loop 迴圈第一次執行時,i 這個變數會被設定為 1,然後執行 s = s + i,接著讓 i 遞增為 2,再執行一次 s = s + i,以此類推,直到 i 遞增到 10 並執行完該次迭代之後,才會跳出 For Loop 迴圈。整個程式執行完之後,就會把 110 的總和算出來:

excel-vba-programming-loop-20161206-1

Excel VBA For Loop 迴圈

Exit For 中斷迴圈

For Loop 迴圈在正常的狀況下會一直執行,直到迭代變數遞增至結束值為止,如果想要中途跳出迴圈,可以加上 Exit For 來中斷迴圈:

Dim i, s As Integer
s = 0
For i = 1 To 10
  s = s + i
  If i >= 4 Then
    Exit For ' 中斷迴圈
  End If
Next i
MsgBox "s = " & s

在這個範例中,我們在 For Loop 迴圈當中加入了一個 If Then 條件判斷式,當 i 大於或等於 4 的時候,就跳出迴圈,所以最後我們會得到從 1 加到 4 的總和:

Excel VBA Exit For 中斷迴圈

For Each 迴圈

For Each 迴圈是 For Loop 迴圈的另外一種精簡寫法,兩者功能差不多,只是在某些狀況下使用 For Each 迴圈會比較方便。

一般若要使用 For Loop 迴圈對陣列中的每個元素逐一處理時,必須明確指定開始與結束的索引值,再以索引值取出陣列中的元素做進一步的運算,而 For Each 迴圈則是可以自動將陣列中的元素逐一取出,放進迴圈的迭代變數中處理,這樣的寫法會比 For Loop 更精簡。

For Each 迭代變數 In 陣列
運算內容
Next 迭代變數

這是使用 For Each 迴圈找出目前 Excel 中所有工作表的範例程式:

Dim wSheet As Worksheet
For Each wSheet In Worksheets
  MsgBox "找到工作表: " & wSheet.Name
Next wSheet

這個 For Each 迴圈會將 Worksheets 中的每一個元素逐一取出,儲存在 wSheet 變數中,並且執行迭代的內容。這個例子會將 Excel 中的每一張工作表取出來,呼叫 MsgBox 輸出每一張工作表的名子,也就是說 Excel 中的工作表有幾張,這個迴圈就會執行幾次。

Excel VBA For Each 迴圈

Do Loop 迴圈

Do Loop 迴圈可以重複執行某一段程式碼,直到指定的條件判斷式成立或是不成立的時候,才停止迴圈的執行,而這類的迴圈有好幾種不同的型式,使用者可以依照需求選擇適合的寫法。

Do While Loop 迴圈

Do While Loop 迴圈可以在每一次迭代時,檢查一個指定的條件判斷式,如果成立的話(判斷為 True)就會繼續執行,而如果條件不成立(判斷為 False)的話,就會中止迴圈。

Do While 條件判斷式
運算內容
Loop

以下是一個使用 Do While Loop 迴圈計算 110 總和的範例。

Dim i, s As Integer
s = 0
i = 1
Do While i <= 10
  s = s + i
  i = i + 1
Loop
MsgBox "s = " & s

在這個例子中,一開始先初始化兩個變數,s 變數用於儲存總和值,而 i 則是用於每次迭代的變數,迴圈執行時會先判斷 i 是否小於或等於 10,如果條件成立則執行迴圈的內容,一直重複執行直到 i 大於 10 為止,所以最後得到的 s 就是 110 的加總數值。

Excel VBA Do While Loop 迴圈

While 的條件判斷式也可以放在迴圈結尾處,這樣的話迴圈在執行時就會先執行第一次的迭代,執行完第一次之後才判斷是否要繼續執行下一次的迭代,如果條件成立則繼續執行,若不成立就立刻中止迴圈,這樣的寫法只是檢查條件判斷式的時機不同,觀念上大同小異。

Do
運算內容
Loop While 條件判斷式

以下是一個簡單的範例。

Dim i, s As Integer
s = 0
i = 1
Do
  s = s + i
  i = i + 1
Loop While i <= 10
MsgBox "s = " & s

Do Until Loop 迴圈

Do Until Loop 迴圈與 Do While Loop 迴圈在條件的判斷上剛好相反,Do Until Loop 迴圈會在指定條件不成立(判斷為 False)時繼續執行,當判斷條件成立時(判斷為 True)則終止迴圈。

Do Until 條件判斷式
運算內容
Loop

以下是一個 Do Until Loop 迴圈的範例程式碼。

Dim i, s As Integer
s = 0
i = 1
Do Until i > 10
  s = s + i
  i = i + 1
Loop
MsgBox "s = " & s

Do Until Loop 迴圈也可以將條件判斷式放在迴圈的最後面,這跟上面 Do While Loop 迴圈也很類似。

Do
運算內容
Loop Until 條件判斷式

以下是一個簡單的範例。

Dim i, s As Integer
s = 0
i = 1
Do
  s = s + i
  i = i + 1
Loop Until i > 10
MsgBox "s = " & s

Exit Do 中斷迴圈

如果要在 Do Loop 迴圈執行到一半時終止迴圈的執行,可以在迴圈中加入 Exit Do,以下是一個範例:

Dim i, s As Integer
s = 0
i = 1
Do Until i > 10
  s = s + i
  i = i + 1
  If i > 4 Then
    Exit Do ' 中斷迴圈
  End If
Loop
MsgBox "s = " & s

在這個例子中,我們在迴圈之中加入一個 If 判斷式,讓程式在 i 大於 4 的時候就執行 Exit Do 跳出迴圈,所以這個程式最後所得到的結果就是從 14 的總和。

Excel VBA Exit Do 中斷迴圈

應用範例

迭代 Excel 工作表

此範例示範如何結合 For Loop 迴圈與 Cells 函數(Cells 函數的用法請參考活頁簿、工作表與儲存格),自動迭代處理 Excel 工作表內的資料:

Dim i, j As Integer
For i = 1 To 3
  For j = 1 To 3
    MsgBox ("(" & i & "," & j & ") = " & Cells(i, j))
  Next j
Next i

迭代 Excel 工作表

更多關於 VBA 的教學文章,請參考 VBA 程式設計

參考資料:ExcelFunctions.netExcel VBA ProgrammingtutorialspointExcel Easystackoverflow

Windows, 程式設計

15 留言

  1. Chen

    VBA的各個教學的寫得淺顯易懂
    幫助很大
    希望大大有空還可以繼續寫更深入的教學文章
    謝謝!

  2. Learning_VBA

    過年期間想要自學VBA 您的文章對初學者幫助很大 謝謝

  3. Lai

    您好,看您教的VBA貼文,讓我學到很多
    非常感謝您
    而我有一個迴圈的問題想請問您
    假如:
    SUB TRY()
    DIM W,S,X AS INTEGER
    W=0
    FOR S= O TO 10
    X=W+S
    IF S>=4 THEN
    EXIT FOR
    END IF
    NEXT S
    MSGBOX “X=” & X
    END SUB

    1.為何X跑出的結果卻是4

    2.上述的解釋不是:
    [算X=W+S的迴圈,當S大於等於4時跳出終止迴圈嗎?]
    3.大於等於4(>=4)不就只要為4或大於是就終止迴圈,所以不是應該只有加1+2+3=6嗎?為何答案為10?

    4.想請問一下,為何把上述的X=W+S改成W=W+S答案跑出來的結果卻不一致呢?
    (是不能為3個變數嗎?可是我一開始有DIM宣告X,W,S為整數阿)

    不好意思,為初學者,所以問題較多!

    • G. T. Wang

      我想您的問題是屬於數學邏輯上的問題,並不是程式語法問題。簡單來說就是您還沒完全想懂這個程式是怎麼跑的,仔細多想幾遍應該就會想通了。

  4. liu

    請問迭代變數可以是sheet裡面的 N2 到 N31 嗎 ?
    已經把”單一個欄位”(即 N2)的 判別 及 後續動作 都寫好,
    但學得不多,
    還沒弄懂如何用LOOP去處理在不同欄位下,同樣的 判別 及 後續動作,謝謝

    • G. T. Wang

      可用 For Loop 配合 Cells,我已將範例加入文章內,請參考文章內容。

      • liu

        T_T … 我成功了~非常感謝,

        念書時期沒想很多,沒考慮過職場中excel的影響力及親切度,

        所以當時用fortran程式,現在整個卡卡,還好有您的教學文,

        太棒了~

  5. YAN

    若我想將第一欄中所有值是”ABC”與空值得欄位刪除,以下這樣寫有什麼錯誤嗎?
    執行完的結果有點詭異,比如說(7,1)和(8,1)都是空值,執行一次後會刪掉一個空值,再執行一次才會兩個空值都刪掉。麻煩您幫忙看一下,感謝。
    Dim i As Integer
    For i = 1 To 874
    If Cells(i, 1).Value = “ABC” Then
    Cells(i, 1).Delete
    ElseIf Cells(i, 1).Value = “” Then
    Cells(i, 1).Delete
    End If
    Next i

  6. YAN

    喔…我想到了,我再刪除了一個欄位後,下方的空值欄位會像上補,所以就刪不到了..顆顆
    感謝你寫的教學。

  7. OWEN

    請問如果B1:B26 中如果有空值就跳出迴圈
    然後匯出TXT 我要怎麼加入判斷

    Dim Rng As Object
    Dim strData

    For Each Rng In Range(“B1:B26”)
    If Rng.Column = 1 Then
    strData = strData & Rng & vbTab
    ElseIf Rng.Column = 2 Then
    strData = strData & Rng & vbCr
    End If
    Next
    Debug.Print strData

    Dim fsT As Object
    Set fsT = CreateObject(“ADODB.Stream”)
    fsT.Type = 2
    fsT.Charset = “UTF-8”
    fsT.Open
    fsT.WriteText strData
    fsT.SaveToFile “D:\ID.txt”, 2
    End Sub

  8. LEE

    請問一下我有類似寫了迴圈的蛋為啥他還是會讀到重複的題目呢?

    Attribute VB_Name = “Module1”
    Dim data(2000, 9), test(100, 9)
    Dim rno, tno

    Sub new_test()
    tno = InputBox(“請輸入考題數:”, , 80)
    Call clean_data
    Call read_data
    Call choice
    Call write_data
    End Sub
    Sub clean_data()
    Worksheets(“W2”).Select
    For i = 2 To 101
    For j = 1 To 9
    Cells(i, j) = “”
    Next
    Cells(i, 9).Interior.Color = xlNone
    Next
    End Sub

    Sub read_data()
    Worksheets(“W1”).Select
    i = 1
    Do While Cells(i, 1) “”
    For j = 1 To 9
    data(i, j) = Cells(i + 1, j)
    Next
    i = i + 1
    Loop
    rno = i – 2
    End Sub
    Sub choice()
    Randomize

    For i = 1 To tno
    no = Int(Rnd * rno) + 1
    For k = 1 To tno
    If no = Val(test(i, 2)) Then Exit For
    Next

    If k < tno + 1 Then
    i = i – 1
    Else
    For j = 1 To 9
    test(i, j) = data(no, j)
    Next
    End If

    Next
    End Sub

    Sub write_data()
    Worksheets("W2").Select
    For i = 1 To tno
    Cells(i + 1, 1) = test(i, 2)
    Cells(i + 1, 2) = test(i, 3)
    Cells(i + 1, 3) = i
    Cells(i + 1, 4) = test(i, 4)
    Cells(i + 1, 5) = test(i, 5)
    Cells(i + 1, 6) = test(i, 6)
    Cells(i + 1, 7) = test(i, 7)
    Cells(i + 1, 8) = test(i, 8)
    Cells(i + 1, 9) = test(i, 9)

    Next
    End Sub

  9. LEE

    大大你好 我有寫類似迴圈的 可是我的總會獨到重複的?
    大大請問有解嗎?

    Attribute VB_Name = “Module1”
    Dim data(2000, 9), test(100, 9)
    Dim rno, tno

    Sub new_test()
    tno = InputBox(“請輸入考題數:”, , 80)
    Call clean_data
    Call read_data
    Call choice
    Call write_data
    End Sub
    Sub clean_data()
    Worksheets(“W2”).Select
    For i = 2 To 101
    For j = 1 To 9
    Cells(i, j) = “”
    Next
    Cells(i, 9).Interior.Color = xlNone
    Next
    End Sub

    Sub read_data()
    Worksheets(“W1”).Select
    i = 1
    Do While Cells(i, 1) “”
    For j = 1 To 9
    data(i, j) = Cells(i + 1, j)
    Next
    i = i + 1
    Loop
    rno = i – 2
    End Sub
    Sub choice()
    Randomize

    For i = 1 To tno
    no = Int(Rnd * rno) + 1
    For k = 1 To tno
    If no = Val(test(i, 2)) Then Exit For
    Next

    If k < tno + 1 Then
    i = i – 1
    Else
    For j = 1 To 9
    test(i, j) = data(no, j)
    Next
    End If

    Next
    End Sub

    Sub write_data()
    Worksheets("W2").Select
    For i = 1 To tno
    Cells(i + 1, 1) = test(i, 2)
    Cells(i + 1, 2) = test(i, 3)
    Cells(i + 1, 3) = i
    Cells(i + 1, 4) = test(i, 4)
    Cells(i + 1, 5) = test(i, 5)
    Cells(i + 1, 6) = test(i, 6)
    Cells(i + 1, 7) = test(i, 7)
    Cells(i + 1, 8) = test(i, 8)
    Cells(i + 1, 9) = test(i, 9)

    Next
    End Sub

  10. Ben

    以變數作為巢狀迴圈層數,如何更有效率編碼,而非預設好一層包一層,因層數未能預知

  11. Alice

    請問dim設定變數後,需要釋放變數(set x = nothing)嗎?我這樣做都會跳出錯誤訊息。
    還是只有用set設定變數,才需要釋放變數? 謝謝!

Comments are Closed