データのある分だけ、同じ処理を実行させたいときがあります。
そのときに使うのが、For Next文やDo Loop文です。
繰り返し処理の基本は、For Next文です。
決まった回数の繰り返し処理を行うのが得意です。
右のようにしたい
例えば、上のようなデータを、奇数と偶数に振り分ける場合だと、下のようになります。
Sub test() Dim R As Integer For R = 2 To 10 ←@ Select Case Cells(R, 1) Mod 2 ←A Case Is = 1 ←B Cells(R, 2) = Cells(R, 1) Cells(R, 1) = "" Case Else ←C Cells(R, 3) = Cells(R, 1) Cells(R, 1) = "" End Select Next R ←D End Sub |
@ ここで、2行目から10行目まで処理をすることを設定します。 (数が、2から1つずつ増えて、10になるまで処理をする。) A セルの値を2で割った余りで条件分岐します。 B 余りが1のときは、2列目の奇数の欄に書き込み、元のセルは空欄にします。 C それ以外の時は、3列目の偶数欄に書き込み、元のセルは空欄にします。 D ここまでの処理を繰り返すよう設定します。 |
上の書き方が基本ですが、次のようなこともできます。 For R = 2 To 10 Step 2 ← 2から10まで、2つずつ数字を増やしていく。(2つ飛ばしの意味) For R = 10 To 2 Step -2 ← 10から2まで、2つずつ数字を減らしていく。 |
いつも同じ個数のデータを処理する場合は、For Next文で回数を指定すればいいのですが、
毎回、データの数が違うとなると、そのままではうまく処理できません。
そういうときには、便利な Do Loop文があります。
連続してデータが続く場合、終わりまで処理を続けてくれます。
Sub test3() Dim R As Integer R = 2 ←@ Do Until Cells(R, 1) = "" ←A Select Case Cells(R, 1) Mod 2 Case Is = 1 Cells(R, 2) = Cells(R, 1) Cells(R, 1) = "" Case Else Cells(R, 3) = Cells(R, 1) Cells(R, 1) = "" End Select R = R + 1 ←B Loop ←C End Sub |
@ ここで、何行目から実行するか数値を設定します。(カウンタ) A 1列目のセルが空になるまで、処理を実行します。 B カウンタを1つ、増やします。 C ここまでの範囲を繰り返します。 |
Do Loop文では、カウンタという変数を1つ用意し、進み方を設定しなければなりません。B 上の場合でいうと、Rです。 1回処理が終わる毎に、カウンタを1つ増やして、1つ下のセルを指定しています。 これをしないと、同じセルで無限に処理を続けていくことになります。 (For Next文は、行頭で設定しています。) Do の横にある、Until は、「条件を満たすまで実行する」という意味です。 したがって、上の場合は、空のセルが見つかるまで実行し続けます。 反対に、While もあります。(「条件を満たす間実行する」という意味 これを使って同じ処理をさせようとするなら、 Do Until Cells(R, 1) = "" は、下のようになります。 Do While Cells(R, 1) <> "" となります。 また、Until や While は行末に付けることもできます。 Do Loop Until Cells(R, 1) 行頭に付けた場合は、条件が合わないと1回も処理をしずに次に移ってしまうのに対して、 行末にに付けた場合は、必ず1回は処理をします。 このことを考えて、位置を決めます。(普通は、行頭でいいです。わかりやすいから。) |
Do Loop文は、非常に便利ですが、途中に空欄があると、もうお手上げです。
空欄で、処理が止まってしまうからです。
そこで、空欄があっても処理を続けさせるには、ひと工夫してFor Next文を使います。
右のようにしたい
Sub test4() Dim 数 As Long ←@ Dim R As Long ←@ 数 = Rows.Count ←A 数 = Cells(数, 1).End(xlUp).Row ←B For R = 2 To 数 ←C Select Case Cells(R, 1) Mod 2 Case Is = 1 Cells(R, 2) = Cells(R, 1) Cells(R, 1) = "" Case Else Cells(R, 3) = Cells(R, 1) Cells(R, 1) = "" End Select Next R End Sub |
@ 変数の宣言を長整数型で行います。 整数型(Integer)だと、オーバーフローしてしまうからです。 A セルの全行数を求めます。 B 最終行から、データのある最終行を探します。 C 範囲を2から、データのある最終行とします。 |
工夫してあるのは、@、A、Bで、データの最終行を求めていることです。 これで、空欄があっても最後まで処理してくれます。 |
For文の使い方として、『ある範囲や全ワークシートなどを対象にして繰り返し処理を行う』というものがあります。
位置などの変数を使わなくてもいいので、上手に使うと非常に便利です。
ある範囲で実行 (実行前) → |
→ ある範囲で実行 (実行後) |
Sub test01() Dim 範囲 As Range ←@ Dim tmp As Range ←A Set 範囲 = Range("a1:d5") ←B For Each tmp In 範囲 ←C tmp.Value = tmp.Value + 1 ←D Next tmp End Sub |
≪ある範囲の数値全部に、1を足す処理≫ @A セルや範囲を扱うのでRangeで宣言します。 B 範囲という変数に代入します。 C 範囲の中から、1つずつセルを取り出します。 D tmpがセルを扱っているので、セルの何を扱うのか、細かく指定します。 この場合は、値なので、Value です。 入っている値に、+1したものを元のセルに代入しています。 |
全ワークシートを対象に実行 (実行前) → | → 全ワークシートを対象に実行 (実行後) |
Sub test02() Dim tmp As Worksheet ←@ Dim R As Integer For Each tmp In Worksheets ←A R = R + 1 ←B Cells(R, 1) = tmp.Name ←C Next tmp End Sub |
≪すべてのワークシート名をセルに書き出す処理≫ @ ワークシートを扱うのでWorksheetで宣言します。 A 全ワークシートの中から、1つずつワークシートを取り出します。 B 書き込むセルを1つずつ下に下げるため、+1します。 C tmpがワークシートを扱っているので、ワークシートの何を扱うのか、細かく指定します。 この場合は、名前なので、Name です。 全部のワークシートの名前を、セルに書き出しています。 |
全オートシェイプを対象に実行 (実行前) → |
→ 全オートシェイプを対象に実行 (実行後) |
Sub test03() Dim tmp As Shape ←@ Dim L As Integer For Each tmp In ActiveSheet.Shapes ←A tmp.Top = 0 ←B tmp.Left = L ←C L = L + 80 ←D Next tmp End Sub |
≪すべてのシェイプを順に並べる処理≫ @ シェイプを扱うので、Shapeで宣言します。 A アクティブなシートの全シェイプの中から、1つずつシェイプを取り出します。 B ワークシート上でのシェイプの上端の位置を決めます。ここでは0なので、シートの一番上になります。 C ワークシート上でのシェイプの左端の位置を決めます。ここでは80ずつ増やしていくので、右に順番に並びます。 |