VBScriptは、Windows環境でスクリプトを実行するための強力なツールです。
特に繰り返し処理を効率的に行うためには、for文を使いこなすことが不可欠です。
この記事では、VBScriptにおけるfor文の基本から応用までを詳しく解説し、演習問題と解答例も提供します。
for文の基本構文
forは「対して」という英単語で、for文は、特定の回数だけ繰り返し処理を行うために使用されます。
基本的な構文は次のとおりです。
For counter = start To end [Step stepValue]
' 繰り返し処理するコード
Next
- counter: ループの現在の反復回数を示す変数です。
- start: ループの開始値です。
- end: ループの終了値です。
- stepValue: ループカウンタの増分(デフォルトは1)です。
for each文との違い
for文は数値の範囲を指定して繰り返しを行いますが、for each文はコレクションや配列の要素を順番に処理します。例えば、配列の要素を表示するにはfor each文を使用します。
Dim fruits
fruits = Array("Apple", "Banana", "Cherry")
For Each fruit In fruits
WScript.Echo fruit
Next
このスクリプトでは、配列の各要素が順番に表示されます。
若い要素番号から順番に取得し、処理を繰り返します。
ループ処理を終了させる
for文のループ(繰り返す)処理を強制的に終了させたい場合があると思います。
for文の中で「Exit For」を記述するだけで、ループ処理を終了することができます。
'変数の宣言と初期化
Dim aiueo : aiueo = "あいうえお"
'文字列の桁数分ループする
For i = 1 To Len(aiueo)
'文字列から1文字を取得
Dim chrTmp : chrTmp = Mid(aiueo,i,1)
'forから抜ける
If chrTmp = "い" Then Exit For Else
'結果を確認 → あ
Msgbox chrTmp
Next
Len関数により、変数「aiueo」の文字数(5)を取得し、変数「i」が1、2、3、4、5の5回分繰り返し処理されます。
「i」が1の時、Mid関数により変数「aiueo」(引数1)の1桁目(引数2)を1桁分(引数3)抽出し、文字「あ」を変数「chrTmp」にセットしています。
次に、if文で変数「chrTmp」が「い」の場合、for文を抜けますが、変数「chrTmp」は「あ」のため、スルーされます。
次に、変数「chrTmp」の「あ」がメッセージボックスで出力されます。
一連の処理が終わり、次のループへ行きます。
forの「Step 増減値」がない場合は、1ずつ増加されるので「 i + 1」されて「i」が「1」から「2」になります。
「i」が2の時、Mid関数により文字「い」を変数「chrTmp」にセットしています。
次に、if文で変数「chrTmp」が「い」なので、for文を抜けます。
結果、メッセージボックスで出力されたのは「あ」のみです。
ネストされたFor文
for文をネスト(入れ子)させることで、多重ループを作成することができます。
For i = 1 To 3
For j = 1 To 3
MsgBox "i: " & i & ", j: " & j
Next
Next
次のループへスキップする
次のループ処理へスキップする方法は、2パターンあります。「for文の中にif文」または「for文の中にfor文」です。それぞれご紹介します。
for文の中にif文
'変数の宣言と初期化
Dim aiueo : aiueo = "あいうえお"
'文字列の桁数分ループする
For i = 1 To Len(aiueo)
'文字列から1文字を取得
Dim chrTmp : chrTmp = Mid(aiueo,i,1)
'お以外は、次のループへスキップする
If chrTmp = "お" Then
'結果を確認 → お
Msgbox chrTmp
Else
End If
Next
Len関数により、変数「aiueo」の文字数(5)を取得し、変数「i」が1、2、3、4、5の5回分繰り返し処理されます。
「i」が1の時、Mid関数により変数「aiueo」(引数1)の1桁目(引数2)を1桁分(引数3)抽出し、文字「あ」を変数「chrTmp」にセットしています。
次に、if文で変数「chrTmp」が「お」の場合、メッセージを表示します。
それ以外の場合は、何もしないので結果的に次のループへスキップされます。
そのため、変数「chrTmp」が「あ」「い」「う」「え」のときのメッセージの表示は、スキップされ「お」のみがメッセージで表示されます。
つまり、スキップしたい処理をif文で囲むことで実装できます。
for文の中にfor文
'変数の宣言と初期化
Dim aiueo : aiueo = "あいうえお"
'文字列の桁数分ループする
For i = 1 To Len(aiueo)
'文字列から1文字を取得
Dim chrTmp : chrTmp = Mid(aiueo,i,1)
'次のループへスキップするためにループ処理を1回行う
For j = 1 To 1
'次のループへスキップ
If chrTmp <> "お" Then Exit For Else
'結果を確認 → お
Msgbox chrTmp
Next
Next
「for文の中にif文」で解説した内容とほとんど同じで、変数「chrTmp」が「お」以外の場合に2個目のfor文から抜けることで結果的に次のループへスキップされます。
そのため、変数「chrTmp」が「あ」「い」「う」「え」のときのメッセージの表示は、スキップされ「お」のみがメッセージで表示されます。
つまり、スキップしたい処理をfor文で囲み「Exit For」することで実装できます。
また、「for文の中にfor文」ではなく「for文の中にdo loop文」でも実装できます。
やっていることは同じなので省略します。
おすすめ
私は、「for文の中にif文」の方法をおすすめします。
for文やdo loop文は、そもそも処理を繰り返したいときに使用するものなので、次のループへスキップする処理として少し意味合いが異なります。
一般的に第三者がコードを見たときに、for文よりif文で記述された方がわかりやすいです。
「for文の中にif文」で書く方が無難でしょう。
サンプルコード
文字列の桁数、配列の要素、Listの要素、Dictionaryの要素、ファイル数などよく使用されていそうな記述例をご紹介し、解説していきます。
数値の繰り返し処理
For i = 1 To 5
MsgBox "Count: " & i
Next
「i」の「1」が「5」になるまで繰り返すことで5回繰り返して処理を行います。
ステップ値の指定
For i = 1 To 10 Step 2
MsgBox "Count: " & i
Next
iの「1」が2ずつ増加され、iが「1」「3」「5」「7」「9」のとき繰り返し処理を行います。
逆順の繰り返し処理
For i = 10 To 1 Step -1
MsgBox "Count: " & i
Next
i」の「10」が「1」になるまで繰り返すことで10回繰り返して処理を行います。
文字列の桁数分ループ
'変数の宣言と初期化
Dim aiueo : aiueo = "あいうえお"
'文字列の桁数分ループする
For i = Len(aiueo) To 1 Step -1
'結果:お → い → う → え → お
Msgbox Mid(aiueo,i,1)
Next
Len関数により、変数「aiueo」の文字数(5)を取得し、開始番号「i」にセットしています。
「i」が5の状態で一度、中の処理が実行されます。Mid関数により、変数「aiueo」(引数1)の5桁目(引数2)を1桁分(引数3)抽出し、文字「お」がメッセージに表示されます。
次に、Stepの「-1」によって、「 i + -1」されて「i」が「5」から「4」になります。中の処理が実行され、「え」がメッセージに表示されます。
これを「i」が「1」になるまで繰り返すことで「お → え → う → い → あ」の順番でメッセージが表示されています。
配列の要素分ループ
'変数の宣言と初期化
Dim aryMozi: aryMozi = Array("要素1","要素2","要素3")
'配列の要素分ループする
For Each index In aryMozi
'結果:要素1 → 要素2 → 要素3
msgbox index
Next
変数「aryMozi」に配列を代入し、aryMoziの1番目の要素であるaryMozi(0)には、”要素1″が入っていて、aryMozi(1)には”要素2″、aryMozi(2)には”要素3″が入っている状態です。
若い要素番号から順番に取得されるため、「要素1 → 要素2 → 要素3」の順番でメッセージが表示されています。
Listの要素分ループ
'変数の宣言
Dim objList : Set objList = CreateObject("System.Collections.ArrayList")
'追加
objList.Add "要素1"
objList.Add "要素2"
objList.Add "要素3"
'リストの要素分ループする
For Each index In objList
'結果:要素1 → 要素2 → 要素3
msgbox index
Next
'後始末
Set objList = Nothing
変数「objList」に作成したリストをセットし、objListに”要素1″、”要素2″、”要素3″の文字を追加します。
若い要素番号から順番に取得されるため、「要素1 → 要素2 → 要素3」の順番でメッセージが表示されています。
Dictionaryの要素分ループ
'変数の宣言
Dim objDic : Set objDic = CreateObject("Scripting.Dictionary")
'追加
objDic.Add "キー1", "値1"
objDic.Add "キー2", "値2"
objDic.Add "キー3", "値3"
'Dictionaryの要素分ループする
For Each key In objDic.keys
'結果:キー1値1 → キー2値2 → キー3値3
msgbox key & objDic(key)
Next
'後始末
Set objDic = Nothing
変数「objDic」に作成したDictionaryをセットし、objDicにキーと値の文字を追加します。
若い要素番号から順番に取得されるため、「キー1値1 → キー2値2 → キー3値3」の順番でメッセージが表示されています。
ファイル数分ループ
'ファイル操作用のオブジェクトを作成
Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
'このvbsのフルパスを取得
Dim fullPath : fullPath = objFSO.GetAbsolutePathName(WScript.ScriptName)
'フルパスからフォルダー名を取得
Dim dirPath : dirPath = objFSO.GetParentFolderName(fullPath)
'フォルダー内のオブジェクトを取得
Dim objDir : Set objDir = objFSO.GetFolder(dirPath)
'ファイル数分ループする
For Each file In objDir.Files
'結果:実行したvbsファイルと同階層のファイル名が表示される
msgbox objFSO.GetFileName(file)
Next
'後始末
Set objDir = nothing
Set objFSO = nothing
ファイル操作を行うためのオブジェクト「Scripting.FileSystemObject」を作成し、セットします。
次に、実行されたvbsファイルの絶対パス(フルパス)を取得します。
フルパスからファイル名を除いたフォルダーのパスを取得します。
最後に、取得したフォルダーのパスにあるオブジェクトを取得します。
最後に取得したオブジェクトからファイルのオブジェクトだけを指定します(objDir.Filesの部分)。
ファイル名の昇順で取得され、メッセージが表示されます。
for文とwhile文の違い
for文とwhile(do loop)文は、どちらも繰り返し処理を行うためとても似ていて、なんとなくで使い分けている方も多くいらっしゃるのではないでしょうか。
for文は、繰り返す回数が決まっている場合に使用します。
while文は繰り返す回数が決まっていない場合に使用します。
ここまで紹介した配列の要素数分ループするといった処理は、while文でもインクリメント用の変数を用意することで実装することは可能です。
しかし、while文の中でインクリメントする処理を記述し忘れたまま実行すると、処理が終わらない「無限ループ」に陥ります。
無限ループは、ものすごい数の処理が繰り返されるため、PCに強い負荷がかかり、フリーズ(アプリが固まる)します。
最悪の場合、PCの故障の原因にもつながるため可能であれば、for文を使用することをオススメします。
for文とwhile文はどちらが速いか
for文とwhile(do loop)文は、どちらも繰り返し処理を行います。
繰り返す回数が決まっている場合は、どちらでも実装できます。
しかし、プログラムは処理が速いほど処理時間が短くなるので、処理速度をみなさん意識していると思います。
そこでどちらが速いか検証しましたので、参考にしてください。差し支えなければ、下記2つのコードをみなさんも試して速い方を教えてください。
計測例:for文
'変数を定義
Dim sumVal : sumVal = 0 '計測値の合計値
Dim ROOP_SU : ROOP_SU = 1000 '計測回数
'計測回数分ループする
For i = 1 To ROOP_SU
'計測開始時間
Dim t1 : t1 = Timer
'計測する処理
For j = 0 To 1000000
test = "test"
Next
'計測終了時間を加算
sumVal = sumVal + (Timer - t1)
Next
'ファイルシステムオブジェクトの作成
Set fso = CreateObject("Scripting.FileSystemObject")
'結果を出力
Set file = fso.OpenTextFile(".\for:平均" & (sumVal / ROOP_SU) & "秒.txt", 8, True)
'ファイルを閉じる
file.Close
'後始末
Set fso = Nothing
'お知らせ
msgbox "処理完了"
計測例:while文
'変数を定義
Dim sumVal : sumVal = 0 '計測値の合計値
Dim ROOP_SU : ROOP_SU = 1000 '計測回数
'計測回数分ループする
For i = 1 To ROOP_SU
'計測開始時間
Dim t2 : t2 = Timer
'計測する処理
Dim cnt1 : cnt1 = 0
Do while cnt1 <= 1000000
test = "test"
cnt1 = cnt1 + 1
Loop
'計測終了時間を加算
sumVal = sumVal + (Timer - t2)
Next
'ファイルシステムオブジェクトの作成
Set fso = CreateObject("Scripting.FileSystemObject")
'結果を出力
Set file = fso.OpenTextFile(".\while:平均" & (sumVal / ROOP_SU) & "秒.txt", 8, True)
'ファイルを閉じる
file.Close
'後始末
Set fso = Nothing
'お知らせ
msgbox "処理完了"
for文は平均約0.17秒で、while(do loop)文は、平均約0.30秒になりました。
for文の方が処理が速いです。
しかし、あくまでもVBScriptでの結果です。
プログラミング言語によってはwhile文の方が速い場合もあるようです。
また、パソコンのスペックによっても計測結果は変わりますのでご了承ください。
演習問題
以下に、for文に関するいくつかの演習問題を用意しました。挑戦してみてください。
演習1
1から20までの数字のうち、偶数だけを表示するスクリプトを書いてください。
演習1 解答例
For i = 2 To 20 Step 2
WScript.Echo i
Next
演習2
1から10までの数字を逆順に表示し、それぞれの数字に対してその2倍の値も一緒に表示するスクリプトを書いてください。
演習2 解答例
For i = 10 To 1 Step -1
WScript.Echo i & " : " & (i * 2)
Next
演習3
Arrayを使用して、5つの好きな言葉を配列に格納し、それぞれをfor文を使って表示するスクリプトを書いてください。
演習3 解答例
Dim words
words = Array("Hello", "World", "VBScript", "Loop", "Example")
For i = 0 To UBound(words)
WScript.Echo words(i)
Next
まとめ
VBScriptのFor文を使いこなすことで、繰り返し処理を効率的に行うことができます。
カウンター変数や範囲、ステップ値を適切に設定し、必要に応じてネストやExit For文を使って柔軟にループを制御しましょう。