皆さまこんにちは!
このサイトの管理者のHide(ヒデ)と申します。
今回はExcel-VBAで利用されるDo While文についてお伝えしたいと思います。Do While文はループ文とも呼ばれていて、同じ命令を繰り返し実行したい場合に利用できるプログラミングの文法です。
このDo While文がどのようなものか、詳しく見ていきましょう。
Contents
1. Do While文とは
Do While文を少しずつ理解するために、まずは、下記のTestという名前のプログラムをご覧ください。
Sub Test()
プログラムの命令その1
プログラムの命令その2
プログラムの命令その3
End Sub
これまで、プログラムは上から下に順番に実行されるということをお伝えしてきました。上記のプログラムも同じで「プログラムの命令その1」→「プログラムの命令その2」→「プログラムの命令その3」の順番で命令が実行されていきます。
では、例えば「プログラムの命令その2」の部分について3回実行したい場合、どのようにプログラムを書けばよいでしょうか。例えば下記のような書き方が考えられます。
Sub Test()
プログラムの命令その1
プログラムの命令その2
プログラムの命令その2
プログラムの命令その2
プログラムの命令その3
End Sub
上記のように同じ命令を3回記述するという方法ですね。では、「プログラムの命令その2」の部分を100回実行したいとしたらどうでしょう。3回ならまだ上記の書き方でよいですが、100回となるととても大変ですし、同じ命令を100回書くのはとても非効率に思えてきます。そこで利用するのがDo While文になります。
2. Do While文の文法
さて、このプログラムの説明ですが、どこかで見たことがありますね。そうです。このDo While文ですが、以前のブログでご紹介したFor文と同じ役割があるのです。
但し、For文とDo While文を比べると、その機能において少し性格が異なります。For文はループ変数の初期値と終了値を設定して決められた回数だけプログラムの命令を繰り返す印象が強いのに対し、Do While文はこのFor文と同じ使い方ができるだけでなく、プログラムを実行してみないと何回命令を繰り返すか不明なケースでも利用できるという特徴があります。
では、まず初めにFor文と同じ動きをするDo While文の書き方(文法)について下記にご紹介致します。
Dim 変数名 As Long
変数名=初期値
Do While 変数名<= 終了値
プログラムの命令
変数名=変数名+増分値
Loop
上記がDo While文の基本形となります。Do While~LoopまではDo While文の骨格となる部分です。このDo While文はDo Loop文や単にDo文と呼ぶこともあります。Do文にはいくつかの形がありますが、本ブログでは最も利用頻度の高いDo While文について解説しています。
以前ご紹介したFor文では繰り返しの回数などを制御するために「ループ変数」と呼ばれる整数を扱う変数を用意する必要がありましたが、Do While文でもFor文と同じ使い方をする場合には、同様にループ変数を用意する必要があります。上記の文法の変数名と書かれた部分がそれに当たります。ループ変数といっても普通の変数です。整数を格納できる変数を用意すればよいので、変数の型としては扱う数の大きさにもよりますがIntegerかLongを型として設定すればOKです。
変数の型とは何かについて知りたい方は下記のブログもご覧ください。
Do While文の中に「初期値」,「終了値」,「増分値」とありますが、この部分でプログラムの命令を繰り返す回数を制御します。この点については後述しますね。
次にLoopという部分がありますが、LoopはDo While文の終端を表しています。そしてDo WhileとLoopの間に繰り返し実行したい「プログラムの命令」を記述します。「プログラムの命令」の先頭にスペースがあるのは、If文のブログでもご紹介した字下げといって、プログラムを見やすくする工夫になります。
では具体的な例で考えてみましょう。プログラムの命令を3回繰り返したい場合、Do While文では下記のように記述します。※Do While文に必要な箇所だけ抜粋して記載しています。便宜上、行番号を付けていますが、実際には記述しませんのでご注意ください。
<記述例その1>
01. Dim i As Long
02.
03. i=1
04. Do While i<=3
05. プログラムの命令その1
06. i=i+1
07. Loop
08.
09. プログラムの命令その2
10. プログラムの命令その3
このように記述することで「プログラムの命令その1」の部分を3回繰り返すという動きを表現できるのですが、その仕組みについて下記の解説の部分でご説明したいと思います。(※02,08行目については空白行でプログラムを見やすくする行になりますので、プログラムの命令は実行されません。)
<解説>
Do While文のプログラムの動きについて:
【Step1】
まず、01行目で変数を「i」という名前でDo While文に必要なループ変数を宣言しています。Do While文をFor文と同様に利用する場合、For文と同様に整数を格納できる変数の宣言が必要になると覚えてください。変数名は(予約語が利用できない,先頭を数字にできない等、若干制限はありますが)自由に決めることができます。
補足:予約語とはExcel-VBAの文法で利用される「Sub」や「If」などの既に役割が決まっている用語のことです。
【Step2】
次に03行目に処理が移ります。「i=1」と書かれていますね。このように記述することでループ変数「i」に初期値として「1」が代入されます。For文と異なり、Do While文ではループ変数の初期化の文が一体化されておらずプログラミングする人が忘れずに記述する必要があります。
【Step3】
次に04行目に処理が移ります。「Do While」と記述して、半角スペースを1つ空けた後、「i<=3」と記述されています。この「i<=3」の部分ですが、Do While文における条件式と呼ばれます。この部分はIf文における条件式の判定と同じものとお考えください。
つまり「i<=3」の意味は「変数iの中身が3以下だったら(条件式が真(True)だったら)」、Do WhileとLoopの間に記述されているプログラムの命令を実行しなさいという意味になります。「Do WhileとLoopの間に記述されているプログラムの命令」は、本例では下記の05,06行目の2行になりますね。
05. プログラムの命令その1
06. i=i+1
今回の例では、条件式「iそのため、初めて04行目(Do While文の開始行)に来た時点でループ変数iの初期値が既に終了値を超えていた場合はDo WhileとLoopの間に記述された05行目の「プログラムの命令その1」と06行目の「i=i+1」が一度も実行されずに09行目以降のプログラムに進んでしまうこともあるわけです。
これはどのようなケースかというと例えば今回の例ようにループ変数iの初期値に「1」などの固定値でを設定するのではなく、ループ変数iとは別の変数を宣言して、その変数を初期値として代入して(例:i=jのような形)制御するようなプログラムの場合です。Do While文だからといってDo WhileとLoopの間に記述されたプログラムの命令が必ず(繰り返し)実行されるとは限らないと覚えておいてください。
ここで、06行目の式は右辺において、ループ変数iに現在保持されている内容に「1」を加算した結果を左辺のループ変数iに代入(上書きして更新)している命令になります。本プログラムの場合、ループ変数iの初期値は「1」ですから、06行目が初めて実行された場合、ループ変数iの内容は「2」に変化します。この06行目の記述について初めて見た方、難しいと感じる方は下記の変数について解説したブログもご覧ください。
【Step2】のループ変数の初期化もそうですが、For文と異なり、Do While文ではループ変数を更新する処理が組み込まれておらず、プログラミングする人が忘れずに記述する必要があります。
※補足になりますが、05行目と06行目は逆順に書いてもかまいませんが、処理したいプログラムの命令を全て書いた後にループ変数を更新するという書き方が一般的です。
では、みなさんに質問です。もし06行目のループ変数iの内容を更新する式を記述し忘れたらどうなると思いますか?
先ほどご説明した04行目の条件式の判定のところで、結果が一度「True(真)」になって以降、ループ変数iの内容が更新されず、変数iが終了値「3」を超えないので、永久に05,06行目の命令が実行され続けてプログラムが終わらない状態となります。この状態のことを「無限ループ」と呼びます。そのため、この行はDo While文にとって必須のものとなります。
【Step4】
先ほどご説明した【Step3】のところで、05,06行目が実行された場合は、07行目のLoopと書かれた行が実行されます。
このLoopと書かれた行はDo While文の終端を表しています。このLoop文が実行されると、【Step3】に戻って処理が継続されます。つまりLoop文には、プログラムの処理を上側(Do Whileの開始行)に戻す役割があるのです。
Do While文は、このような流れで処理が進んで行き(ループ変数iの内容は「1→2→3→4」と変化していきます)、【Step3】のところで、条件を満たさなくなり次第(ループ変数iの内容が終了値である「3」を超え次第)、Do While文(04~07行目)を終了して09行目の命令に処理が進みます。
ここまでで、Do While文の動きについて見てきました。文章だけでの説明ではわかりにくいかもしれませんので上記の<記述例その1>のDo While文についてフローチャートを使って見ていきましょう。
3. Do While文のフローチャート
下図は<記述例その1>のフローチャートになります。図の中に解説を記載していますのでじっくりご覧ください。
Do While文のフローチャートはいかがでしたか。このフローチャート内の解説にも書かれていますが、重要な点が1つあります。それは、Do While文の処理が終了した後、次のプログラムに進むのですが、ループ変数iの内容はDo While文の条件式で指定した終了値「3」よりも1つ多い「4」になっているということです。
Do While文を習いたての頃は、Do While文が終了した後のループ変数iの内容は、終了値である「3」になっていると勘違いしやすいのですが、実際には終了値に増分値で設定した値を加算した値になっていることにご注意ください。
今回のプログラムで利用したループ変数iのような変数、またはその変数の値は実際のプログラムでは別の用途で再利用することがあります。その際は、ループ変数の値がどのような状態になっているのか把握した上で利用することが重要です。今回の例では、最終的なループ変数iの値は「4」になりましたが、これは別の章でご説明しますが、Do While文を途中で中断するようなケースでは、別の値になることもありますので、ループ変数を再利用する際には注意して利用するようにしましょう。
ここで3点ほど補足させて頂きます。
1点目:<記述例その1>のDo While文はループ変数の初期値を「1」,終了値を「命令を繰り返したい回数」,増分値を「1」にして「1」ずつカウントアップしていくというDo While文の代表的な使い方になります。但し、あらかじめ繰り返したい回数が明確な場合は、好みの問題もありますが、For文を使った方が分かりやすいと言えます。数学的に言えば、Do While文の変数iは初項が「1」,公差が「1」の等差数列の動きになっています。数学嫌いの方ごめんなさい。
※For文については下記のブログもご覧ください。
For文について解説したブログはこちら
2点目:本ブログではDo While文の基礎を理解頂くためにDo While文の初期値,終了値,増分値に直接数字を指定していますが、実際のプログラムでは変数を記述して可変式にすることも可能です。
3点目:<記述例その1>のDo While文で「プログラムの命令その1」を3回実行することが可能ですが、たとえば下記のように書くことも可能です。
<記述例その2>
01. Dim i As Long
02.
03. i=3
04. Do While i>=1
05. プログラムの命令その1
06. i=i-1
07. Loop
08.
09. プログラムの命令その2
10. プログラムの命令その3
この例は変数iの初期値を「3」からスタートして「1」ずつ減算していき、終了値の「1」より小さくなったら、つまり変数iが「0」になったらDo While文(04~07行目)を終了する動きになります。このように書いても「プログラムの命令その1」を3回実行できますが(※)、プログラムがわかりにくくなるので一般的には<記述例その1>の形を用います。
※について:この書き方は、本ブロブの冒頭でお伝えしたDo While文の文法を下記のように書き換えたものです。このような書き方も可能です。
Dim 変数名 As Long
変数名=初期値
Do While 変数名>=終了値
プログラムの命令
変数名=変数名-減算値
Loop
それでは上記のフローチャートと同じようにDo While文で命令を3回繰り返し実行するプログラムを作ってみましょう。
4. 実際にプログラムを動かしてみましょう
4-1. モジュールを追加する
今回、VBEの画面で下図のように新しいモジュールを追加して、赤枠部(1番)のように名前を「Mo05_Do」としました。また、モジュールを追加した際に赤枠部(2番)のようにコード画面の先頭に「Option Explicit」という文字が挿入されていることを確認してください。
モジュールの作成方法や名前の変更方法については、下記のブログをご覧ください。
モジュールの作成方法について解説したブログはこちら
モジュール名の変更方法について解説したブログはこちら
4-2. プログラムを入力する
モジュールが追加できたら、プログラムを入力してみましょう。今回は下記のようなプログラムを考えてみました。このプログラムはDo While文によって「イミディエイトウィンドウに現在の変数の内容を表示する」命令を3回繰り返した後、このDo While文終了後に「イミディエイトウィンドウに現在の変数の内容を表示する」命令を再度実行します。
Sub DoTest1()
Dim i As Long
i=1
Do While i<=3
Debug.Print "変数iの値は" & i & "です。"
i=i+1
Loop
Debug.Print “変数iの値は” & i & “です。”
End Sub
では、このプログラムをVBEのコード画面に入力してみましょう。入力すると下図のようになります。みなさんもできましたか?
4-3. 1行ずつプログラムを動かしてみる
プログラムは入力できましたでしょうか。それではプログラムを動かしてみましょう。通常、プログラムの動かす場合、動かしたいプログラムの中(このプログラムであれば、Sub DoTest1() と End Sub の間)にカーソルを置いてF5キーを押します。
この方法でもよいのですが、今回はステップ実行というプログラムを1行ずつ動かせる便利な機能を使って動かしてみたいと思います。カーソルを上記のようにプログラムの中に置いた状態でキーボードのF8キーを1回押してみてください。すると下図のように、プログラムの先頭が黄色でハイライトされました。
続いて、F8キーを2回押してみましょう。すると下図のように(Dimから始まる変数の宣言の部分はプログラムの命令ではないので通過し、i=1の行でループ変数を初期化した後)Do While文の開始位置がハイライトされました。
上図でハイライトされたDo Whileの行はこれから実行されることを表していてまだ実行されていません。
この時点でDo While文の行の変数iの上付近にマウスのカーソルを近づけてみましょう。すると下図の赤枠部のように変数iの内容が「1」になっています。変数iは宣言直後の内容は「0」ですが、先ほど「i=1」の式(命令)が実行されたことで、ループ変数が正しく初期化されたことを示しています。また、Do While文の条件式である「i
さらに、F8キーを1回押してみましょう。すると下図のようにDo WhileとLoopの間にある「Debug.Print “変数iの値は” & i & “です。”」の行がハイライトされました。
黄色でハイライトされている行はこれから実行される命令を表していてまだ実行されていません。実際、画面では何も起きていないと思います。
では、もう1回、F8キーを押してみましょう。すると下図のようにイミディエイトウィンドウに「変数iの値は1です。」と表示されました。
※Debug.Printはその右側に書かれた文字や数値,変数の内容を表示して改行する命令でしたね。表示したい文字は「"(ダブルクォーテーション)」で囲みます。また「&」記号で「文字と文字」や「文字と変数」などを連結することができます。
これでDo WhileとLoopの間の命令の1つ目が実行されたことになります。また同時にi=i+1 の行がハイライトされました。
この時点で再度変数iの内容を見てみましょう。プログラムの中の変数iが記述された場所であればどこでもよいのでマウスカーソルを近づけてみましょう。例えば、i=i+1 の行の変数iの上にマウスカーソルを近づけてみると下図のようになりました。この時点ではまだ変数iの内容は「1」だとわかりますね。
では、もう1回、F8キーを押してみましょう。すると下図のようにLoopの行がハイライトされました。
このLoopの行は、Do While文の終端を表しています。このLoopはDo While文の開始行に処理を戻す役割があります。この時点で変数iの上付近にマウスカーソルを近づけてみましょう。すると下図のように変数iの値が「2」になりました。これは、前行の i=i+1 の命令が実行されたことによります。
続いてもう1回、F8キーを押してみましょう。すると下図のようにDo Whileの開始行にハイライトが戻りました。
この時点で変数iの上付近にマウスカーソルを近づけてみましょう。すると下図のように変数iの内容は先ほど1度確認しましたが、「2」ですから、このDo While文の条件式である「i<=3」を満たしていますね。したがってDo WhileとLoopの間に記述された命令が引き続き実行されることになります。
では、イミディエイトウィンドウに下図のように「変数iの値は3です。」と表示されるまでF8キーを押してみましょう。ここまでで、Do While 文により命令が3回繰り返されたことがお分かり頂けるかと思います。
一方、プログラムにおいては、下図のように i=i+1 の行がハイライトされました。
この時点でi=i+1の行の変数iの上付近にマウスのカーソルを近づけてみましょう。すると下図の赤枠部のように変数iの内容はこの時点ではまだ「3」だとわかります。
ではもう1回、F8キーを押してi=i+1の行で再度、変数iの内容を確認してみましょう。すると下図の赤枠部のように変数iの内容は「4」に変わりました。
一方、プログラムにおいては、下図のように Loop の行がハイライトされました。
ではもう1回、F8キーを押してみましょう。すると下図のようにDo Whileの開始行にハイライトが戻りました。
この時点で変数iの上付近にマウスカーソルを近づけてみましょう。すると下図のように変数iの内容は、先ほども1度確認しましたが「4」になっていますね。ここで、Do While文の条件式である「i
では、Do While文が本当に終了するか確認するために、もう1回F8キーを押してみましょう。すると下図のように確かにDo While文の処理を終了してプログラムの最後の命令の行が黄色でハイライトされました。
ではあと2回、F8キーを押してみましょう。これでプログラムの実行は終了となりますが、イミディエイトウィンドウは下図のようになりました。下図の赤枠部のメッセージは、Do While文の外側にあるDebug.Printの文の命令で表示されたものです。変数iの内容は「4」になっていることがわかりますね。
ここまでで、For文と同様の動きをするDo While文のプログラムの基本的な動きについて見てきました。
続いて、Do While文の真骨頂ともいえるもう1つの書き方(使い方)についてお伝えしていきます。
5. Do While文のもう1つの書き方
5-1. Dir関数について学びましょう。
Do While文のもう1つの書き方(使い方)についてお伝えする前に、Excel-VBAで利用できるDir関数についてお伝えしたいと思います。関数と聞いて難しく感じるかもしれませんが、大丈夫です。少しずつ理解しましょう。この関数を取り上げた理由は、Do While文を学ぶ上で最も適しているからです。
Dir関数にはパソコンのフォルダに存在するファイルを探してそのファイル名を教えてくれる機能があります。Dir関数について説明するために下記に簡単なプログラム(ポイントを抜粋)を書いて見ましたのでご覧ください。
※便宜上、行番号を付けていますが、実際には記述しませんのでご注意ください。
01. Dim FileName As String
02.
03. FileName=Dir("C:\VBA-Test\*.*")
04. Debug.Print FileName
05. FileName=Dir()
06. Debug.Print FileName
07. FileName=Dir()
08. Debug.Print FileName
上記のプログラムを実行する前に、パソコンのCドライブの「VBA-Test」というフォルダの中に「001.txt」,「002.txt」という2つのテキストファイルが存在しているという前提で、上記のプログラムについて解説します。
<解説>
01行目について:
FlieNameという変数名で文字を格納する変数を使うことを宣言しています。
02行目について:
プログラムを見やすくするための空白行で、プログラムの命令は何も実行されません。
03行目について:
FileName=Dir("C:\VBA-Test\*.*")と書かれていますね。Excel-VBAでは、このような「=」で結ばれた式の場合、右辺から処理が行われます。この式の右辺で、Dir関数が使われています。Dir関数はDirの右隣りに()を書き、()の中にフォルダのパス名と探したいファイル名の形式を記述します。今回の例では「C:\VBA-Test\」の部分がフォルダのパス名で「*.*」の部分が探したいファイル名の形式となります。
上記で出てきた「*(半角のアスタリスク)」の文字ですが、プログラムの中では、掛け算で利用されるほかにワイルドカードと言って「0文字以上の任意の文字」という意味でも使われます。また「*.*」の部分について右側の「.*」の部分はファイルの拡張子の部分を表しています。「*.*」と記述することで、任意のファイル名を表すことができます。
この03行目のDir関数は「C:\VBA-Test\」のフォルダにある任意のファイル名を教えてくれるのですが、ファイルが複数ある場合は、その中の1つを選んで教えてくれます。
03行目の左辺にFileNameという変数が書かれています。これは、Dir関数が教えてくれた1つのファイル名を格納するためのものになります。「=」記号には右辺の内容を左辺に格納(代入)する機能があるので、結果としてDir関数が調べてくれた1つのファイル名(例えば「001.txt」)がFileNameという変数に格納されます。
Dir関数は、このように「=」の左辺に文字を格納できる変数を記述し、右辺にDir関数を記述するという使い方をします。
※Excel-VBAにおける「=」の役割については、下記のブログもご覧ください。
変数について解説したブログはこちら
04行目について:
Debug.Print FileName と書かれています。Debug.Print はその右側に書かれた文字や変数の内容をイミディエイトウィンドウに表示する命令になります。03行目でFileName変数にファイル名が1つ格納されていますので、この04行目では、そのファイル名(例えば「001.txt」)がイミディエイトウィンドウに表示されることになります。
05行目について:
FileName=Dir()と書かれています。03行目に出てきたDir関数と違ってフォルダのパス名やファイル名の形式が書かれていませんね。これはDir関数の特徴的な書き方なのですが、一度、フォルダのパス名とファイル名の形式を指定してDir関数を実行している場合(本例では03行目)、同じフォルダから次のファイル名を探す場合、Dir関数の()の中を省略する決まりになっているのです。
まず、05行目の右辺でDir関数が「C:\VBA-Test\」のフォルダに存在するファイルを調べて、03行目の時とは別のファイル名(例えば「002.txt」)を教えてくれます。そしてその結果を左辺の変数FileNameに格納しています。(03行目と同じ変数を使っていますのでFileNameの内容は上書きされます。)
06行目について:
Debug.Print FileName と書かれています。05行目でFileName変数にファイル名が1つ格納されていますので、この06行目では、そのファイル名(例えば「002.txt」)がイミディエイトウィンドウに表示されることになります。
07行目について:
05行目と同様にFileName=Dir()と書かれています。このプログラムの動きも05行目と同様になります。つまり、07行目の右辺でDir関数が「C:\VBA-Test\」のフォルダに存在するファイルを調べて、03,05行目の時とは別のファイル名を教えてくれます。そしてその結果を左辺の変数FileNameに格納しています。(05行目と同じ変数を使っていますのでFileNameの内容は上書きされます。)
ただ、「C:\VBA-Test\」のフォルダの中には元々「001.txt」,「002.txt」の2つのファイルしかないとお伝えしました。ということは07行目のDir関数はどのファイル名を教えてくれるのでしょうか。その答えですが、何もないことを表す文字「""」を教えてくれます。これは半角のダブルクォーテーションをスペースなしで2回続けて書いた文字で空文字やNULL文字と呼ばれます。
つまり、07行目の右辺でDir関数がファイルがもう存在しないことを表す「""」を教えてくれ、その結果が左辺の変数FileNameに格納されます。(05行目でFileNameに格納されたファイル名は「""」で上書きされます。)
08行目について:
Debug.Print FileName と書かれています。この行では07行目で調べたファイル名がイミディエイトウィンドウに表示されますが、先ほどお伝えしたようにFileNameの中身は何もないため、画面には何も表示されないという結果となります。
※Dir関数の注意点:
Dir関数は()に指定したフォルダパスなどを元にそのフォルダに存在するファイル名を教えてくれますが、どのような順序でファイル名を教えてくれるかについてはシステムに依存します。例えば、本プログラムのようにDir関数を複数回実行した場合、フォルダ内でのファイル名の順に探して教えてくれるとは限らないため、ファイル名の順に処理したり、画面に表示したりする場合は、並べ替えのプログラムを書くことが必要となります。現時点では、このようなこともあるのだなと覚えておいてください。
ここまでで、Dir関数の基本的な使い方についてお伝えしました。
5-2. Do While文とDir関数を組み合わせてみましょう。
では、いよいよDo While文の真骨頂とも言えるプログラムを書いてみたいと思います。その前に事前準備がありますので、実際に試されたい方は同じように準備してください。
まず、下図のようにCドライブの直下に「VBA-Test」というフォルダを作成します。
続いて、作成した「VBA-Test」フォルダを開き、フォルダ内でマウスを右クリックすると下図のようにメニューが表示されますので「新規作成」→「テキストドキュメント」の順にクリックします。
すると下図のように「新しいテキスト ドキュメント.txt」というファイルが作成されます。これは中身が空っぽのテキストファイルですが、同じ要領で5つのテキストファイルを作成してください。
ファイルが作成できましたら、それぞれのファイル名を下図のようにリネームしましょう。
ここまでの操作でCドライブの中の「VBA-Test」フォルダに5つのテキストファイルが作成されました。それでは、プログラムを使ってこの「VBA-Test」フォルダの中に存在するファイル名を表示するプログラムを作成してみましょう。これを実現するプログラムは下記のようになります。
Sub DoTest2()
Dim FileName As String
FileName=Dir("C:\VBA-Test\*.*")
Do While FileName <>""
Debug.Print FileName
FileName=Dir()
Loop
End Sub
上記のプログラムについて、説明のために先頭に行番号を付けたものが下記になります。プログラムの名前はDoTest2としました。
01. Sub DoTest2()
02.
03. Dim FileName As String
04.
05. FileName=Dir("C:\VBA-Test\*.*")
06.
07. Do While FileName <>""
08.
09. Debug.Print FileName
10. FileName=Dir()
11.
12. Loop
13.
14. End Sub
ではこのプログラムについて解説していきたいと思います。先に言ってしまうと、このプログラムは本ブログの最初の方でお伝えした<記述例その1>のプログラムと仕組みはほとんど同じなんです。ぜひ<記述例その1>のプログラムと対比しながら解説をご覧ください。
<解説>
01,14行目について
01行目はプログラムの先頭を表し、14行目はプログラムの終端を表しています。
02,04,06,08,11,13行目について
この部分は空白行でプログラムを見やすくするための行となります。この行では処理は何も実行されません。
03行目について
文字を格納するために変数の型をString型としてFileNameという名前で変数を宣言しています。フォルダからファイル名を調べて、その結果(文字)を格納したいのでString型としています。
05行目について
FileName=Dir("C:\VBA-Test\*.*") と書かれていますね。これは先ほど「5-1. Dir関数について学びましょう。」のところで一度解説しました。Dir関数をそのプログラムで初めて利用する場合は、Dir関数の()内にファイルを検索したいフォルダパスとファイル名の形式を指定します。また、この行は<記述例その1>のプログラムでいうところの「i=1」の行に相当します。つまりループ変数の初期化と全く同じなのです。このDoTest2というプログラムのループ変数はFileNameと思って頂いて問題ありません。
この行で、Cドライブの「VBA-Test」フォルダにファイルが1つでも存在すればそのファイル名がFileName変数に格納(代入)されます。もしファイルが1つもなければFileName変数に「""」が入ります。「""」の意味は空文字(文字が何もない)ということです。つまり、ループ変数FileNameの初期化を行っているのです。なぜそのようなことが言えるのかという点については下記の解説をご覧ください。
07~12行目について
Do While文の骨格の部分になります。07行目にDo While FileName <>"" と書かれています。この行の「FileName <>""」の部分がDo While文の条件式になります。「FileName <>""」の意味は「変数FileNameの内容が空文字でなかったら(何か文字が入っていたら)」つまり条件式が「True(真)」だったら、Do WhileとLoopの間に記述されているプログラムの命令を実行しなさいという意味になります。
「<>」の記号はこの左辺と右辺に書かれた内容が等しくないということを表します。
今回の例では、Do WhileとLoopの間に記述されているプログラムの命令とは下記の09,10行目の2行になります。
09. Debug.Print FileName
10. FileName=Dir()
09行目は、変数FileNameに格納されたファイル名をイミディエイトウィンドウに表示する命令となります。
ここで、Do While文の前の05行目でなぜ変数FileNameを初期化する必要があるのか、その理由が分かります。05行目でフォルダ内にファイルが存在しない場合、変数FileNameは空文字になります。その場合、Do While文の条件式は「False(偽)」となるので、Do While~Loopの間の命令を1度も実行させないことができるわけです。ファイルが1つもなければ、そのファイル名を表示する09行目の命令を実行する必要はありませんよね。
10行目の右辺にはDir関数があります。このDir関数の()の中に何も記載されていないのは05行目で一度指定しているためです。10行目の右辺のDir関数が「C:\VBA-Test\」のフォルダに存在するファイル名を新たに1つ教えてくれます。そしてそのファイル名を左辺の変数FileNameに格納(代入)しています。
この10行目ですが、<記述例その1>の「i=i+1」の行に相当します。つまり10行目はループ変数であるFileNameを更新する行ということです。この行があることで、さらにDo WhileとLoopの間に記述された命令を続ける必要があるかの判断材料になります。もしこの行を書き忘れた場合、どうなると思いますか。答えを先に言うと、Do Whileの条件式が「True(真)」のまま変わらないのでDo While文がいつまでたっても終わらない無限ループとなってしまいます。
12行目にはLoopと記述されていますね。この行はDo While文の終端を表していて、Do While文の開始行(07行目)に処理を戻す役割があります。この動きによって、再度Do While文の条件式が判定され変数FileNameが空文字でなければ(ファイル名が何か入っていれば)、09,10行目が実行されるという動きが繰り返されます。
最終的に、このDoTest2のプログラムを実行すると先ほどCドライブの「VBA-Test」フォルダに作成した5つのテキストファイルのファイル名がイミディエイトウィンドウに表示されます。
ここまでで、Do While文のもう1つの書き方についてお伝えしてきました。このDo While文には重要な特徴がいくつかありますので下記にまとめました。
特徴その1:
本ブログの文法のところでもお伝えしましたが「プログラムを実行してみないと何回命令を繰り返すか不明なケースでも利用できる」という点です。今回は事前にフォルダ内に5つのファイルがあるということが分かっていますので、Do WhileとLoopの間に記述された命令が5回繰り返されると分かりますが、もしファイルが存在しなかったりファイルが5つ以上存在しても正しく実行されます。
特徴その2:
Do WhileとLoopの間に記述されたプログラムを繰り返す回数に関する情報を指定していなくても正しく実行されるということです。<記述例その1>のプログラムではループ変数として整数を扱う変数iを使って繰り返す回数を制御していましたが、今回のプログラムではFileNameという文字を扱う変数をループ変数で制御できました。
それでは、このDoTest2のプログラムについてVBEのコード画面に入力して実行してみましょう。
5-3. 実際にプログラムを動かしてみましょう
先ほど、下図のようにVBEの画面のMo05_Doというモジュールに「DoTest1」という名前のプログラムを作成しました。今回のブログではこのプログラムの上側にDoTest2のプログラムを入力していきたいと思います。ちょうど赤矢印の部分に入力しましょう。
プログラムを入力すると下図の赤枠部ようになりました。
プログラムは入力できましたでしょうか。それではプログラムを動かしてみましょう。通常、プログラムの動かす場合、動かしたいプログラムの中(このプログラムであれば、Sub DoTest2() と End Sub の間)にカーソルを置いてF5キーを押します。
この方法でもよいのですが、今回はステップ実行というプログラムを1行ずつ動かせる便利な機能を使って動かしてみたいと思います。カーソルを上記のようにプログラムの中に置いた状態でキーボードのF8キーを1回押してみてください。すると下図のように、プログラムの先頭が黄色でハイライトされました。
ここでキーボードのF8キーを1回押してみましょう。すると、下図のように「FileName = Dir("C:\VBA-Test\*.*")」の行がハイライトされました。この行はこれから実行される行でまだ実行されていません。
では、ここで変数FileNameにマウスカーソルを近づけて、その内容を確認してみましょう。すると下図のように変数FileNameの内容が「""」,つまり空文字であることがわかります。これは変数FileNameが宣言直後の状態でまだ何も変更されていないためです。
では、キーボードのF8キーを1回押してみましょう。すると下図のようにDo While文の開始行がハイライトされました。
ここで変数FileNameにマウスカーソルを近づけて、再度、その内容を確認してみましょう。すると下図の赤枠部のように変数FileNameの内容が「2014_Diary.txt」に変わりました。これは、先ほどの「FileName = Dir("C:\VBA-Test\*.*")」行で、右辺のDir関数の実行によりフォルダ内に存在するファイル名が1つ検索され、その結果が変数FileNameに格納(代入)されたことを示しています。(※ここで検索されるファイル名は環境により異なる可能性があります。)
ここで、Do While文の条件式であるFileName<>"" について考えてみましょう。現在、変数FileNameの内容は空文字ではなく「2014_Diary.txt」ですからこの条件式は成立して「True(真)」になりますね。
ではこの点を踏まえてF8キーを1回押してみましょう。すると下図のように「Debug.Print FileName」の行がハイライトされました。つまり、これからDo WhileとLoopの間に記述された命令が実行されるということですね。
では、F8キーをもう1回押してみましょう。すると下図のようにイミディエイトウィンドウに「2014_Diary.txt」と表示されました。これは「Debug.Print FileName」の行が実行されたことによります。
またプログラムにおいては下図のように「FileName = Dir()」の行がハイライトされました。この行はまだ実行されていませんのでF8キーをもう1回押してみましょう。
すると、下図のようにLoopと書かれた行がハイライトされました。
では、この時点で、変数FileNameにマウスカーソルを近づけて、その内容を確認してみましょう。すると下図の赤枠部のように変数FileNameの内容は「2015_Diary.txt」になっていることがわかります。これは「FileName = Dir()」の行の右辺のDir関数の実行によりフォルダ内に存在するファイル名が新たに1つ検索され、その結果が変数FileNameに格納(上書きして代入)されたことを示しています。
現在、Loopという行がハイライトされていますので、F8キーをもう1回押してみましょう。すると下図のようにDo While文の開始行にハイライトが戻りました。
この時点で、Do While文の条件式にある変数FileNameにカーソルを近づけてみましょう。すると先ほど確認した通り、変数FileNameには「2015_Diary.txt」というファイル名が入っていることが分かります。そのため、この条件式は再び成立して「True(真)」になることが分かりますね。
では、もう1回F8キーを押してみましょう。すると下図のように「Debug.Print FileName」の行が再びハイライトされました。
続けてもう1回F8キーを押してみましょう。すると下図のようにイミディエイトウィンドウに2つ目のファイル名である「2015_Diary.txt」と表示されました。
このような流れでDo WhileとLoopの間に記述されたファイル名を表示する命令とループ変数の更新処理が繰り返し実行されて行きます。
それでは下図のようにイミディエイトウィンドウに5つのファイル名が表示されるまでF8キーを押してみましょう。
この時点で、プログラムにおいては下図のように「FileName = Dir()」の行がハイライトされました。この行はまだ実行されていませんのでF8キーをもう1回押してみましょう。
すると下図のようにLoopの行がハイライトされました。
この時点で変数FileNameにマウスカーソルを近づけてその内容を確認してみましょう。すると、下図のようにFileNameの内容が「""」になっていることがわかります。
これは、先ほどの「FileName = Dir()」の行の右辺のDir関数によりフォルダ内のファイルが全て検索しつくされたので、これ以上のファイルは存在せず、その結果が変数FileNameに格納されたことを示しています。ということは、Do While文の条件式は成立せず「False(偽)」になるはずですね。
では、もう1回F8キーを押してみましょう。すると下図のようにDo While文の開始行にハイライトが戻りました。
この時点でDo While文の条件式にある変数FileNameにマウスカーソルを近づけて内容を確認してみましょう。すると下図のようにFileNameの内容が「""」になっていますので確かにこの条件式は不成立となることが分かりますね。
では、F8キーをもう1回押してみましょう。すると下図のようにEnd Subの行がハイライトされました。この動きから、Do While文の処理が終了してプログラムのステップがプログラムの終了直前に移ったことがわかりますね。
最後にF8キーをもう1回押してプログラムを終了しましょう。
ここまでで、Do While文のもう1つの書き方について、実際にプログラムの動きを見てきました。
5-4. Do While文を利用するポイント
今回、フォルダ内にあるファイル名を画面に表示するためにDo While文を使いました。そもそもなぜDo While文を使う必要があったのでしょうか。それはファイル名を検索するために利用するDir関数が一度にすべてのファイル名を教えてくれないからです。Dir関数は一度実行する度に1つしかファイル名を教えてくれないためDir関数を「何回も繰り返し実行する」ことで全てのファイル名を検索し画面に表示できるわけです。この「何回も繰り返す」というところがポイントです。
Excel-VBAではこの「繰り返す」という処理に該当するものはFor文かDo文のどちらかになります。つまりどちらかを利用することになるのですがFor文は回数があらかじめ決まったものに適しているため、必然的にDo文が候補として残り、今回利用されたというのが経緯です。また、Do文を使わない場合、同じDir関数の命令を何行も書かなければならず、ファイルの存在有無を判定するためにIf文を毎回書かなくてはならなくなります。このようにDo文を使わないと色々と手間が増えることから今回Do文が使われたというわけです。
このように処理を何回も繰り返さないと実現できないケースが出てきたらFor文かDo While文のどちらかを使うなと発想できるようにしましょう。
6. まとめ
長くなりましたが、今回はDo While文とは何かという点とその書き方について2つのパターンを見てきました。このブログを通してFor文とDo While文の共通点や違いについてご理解頂ければと思います。
お疲れさまでした。