LibreOffice Basic 制御構文 繰り返し
For Next構文
繰り返し処理の代表はFor Next構文。指定した回数だけ処理を繰り返すときにそれを用いる。その書式はFor カウンター変数名=開始値 To 最終値 Step 増分値 処理内容 Next
のようになる。Step 増分値を省略すると増分値は1になる。Nextの次にNext カウンター変数名
のようにカウンター変数を置いてもよいが、それは省略可能。
Option Explicitステートメントをモジュールの冒頭に指定している場合は、繰り返し回数を数えるためのカウンターとして使う変数をDim カウンター変数名 As Integer
のように予め宣言しておく必要がある。
次のコードは、掛け算のことを同じ数を繰り返し足す累加法であると考え、For Next構文を用いることによって足し算だけで掛け算の計算をするもの。ただし整数倍なので、かけられる数は小数を許容するが、かける数は小数点以下を切り捨てる。
REM ***** 整数倍を累加法で計算 ***** '変数を明示的に宣言して使う Option Explicit Sub Main '変数を宣言 Dim x As Double Dim y As Double Dim answer As Double '値の入力を促す x = InputBox("数を入力してください") 'Int()の引数にして小数点以下は切り捨て y = Int(InputBox("何整数倍にしますか(小数点以下切り捨て)")) '足し算を整数倍だけ繰り返す Dim i As Double For i=1 To y answer = answer + x Next '計算結果を出力 MsgBox x & "の" & y & "倍は" & answer & "です" End Sub
For i=1 To y answer = answer + x Next
は、answer = answer + x
をy回繰り返すことに等しい。
Int函数は引数として丸括弧の中に与えた実数の整数部だけを返すので、ここでは小数点以下の切り捨てに使った。
For Each構文
配列内の要素分だけ順番に処理を繰り返す場合にはFor Each構文を用いるのが便利かもしれない。その書式はFor Each カウンター変数名 In 配列名 処理内容 Next
のようになる。配列の他にもオブジェクトのコレクションを指定することができる。
次のコードは、五つの要素を入れるInteger型配列aを宣言し、For Next構文を使って1, 2, 3, 4, 5の要素をその配列aに順番に代入し、For Each構文を使ってその配列aの各要素をメッセージボックスに順番に出力するもの。
REM ***** 配列要素の代入と出力をFor構文で実装 ***** '変数を明示的に宣言して使う Option Explicit Sub Main '5つの要素を入れる配列を宣言 Dim a(1 To 5) As Integer '繰り返しに使うカウンター変数を宣言 Dim i As Integer Dim j As Integer '配列aに1から5を順に代入 For i=1 To 5 a(i) = i Next '配列aの要素を順番に出力 For Each j In a() MsgBox a(j) Next End Sub
For Next構文であるFor i=1 To 5 a(i) = a(i) + i Next
は次のコードと等しい。
a(1) = 1 a(2) = 2 a(3) = 3 a(4) = 4 a(5) = 5
For Each構文であるFor Each j In a() MsgBox a(j) Next
は次のコードと等しい。
MsgBox a(1) MsgBox a(2) MsgBox a(3) MsgBox a(4) MsgBox a(5)
Do While Loop構文とDo Loop While構文
ある条件式の結果が真の間だけ処理内容を繰り返すときには、Do While Loop構文かDo Loop While構文を用いる。
Do While Loop構文では処理をする前に条件式の真偽を確認するので、処理内容が一度も実行されない可能性がある。それに対してDo loop While構文では処理内容を一度実行してから条件式の真偽を確認するので、処理内容が一度は必ず実行される。
Do While Loop構文の書式は、Do While 条件式 処理内容 Loop
のようになる。Do Lopp While構文の書式は、Do 処理内容 Loop While 条件式
のようになる。
次のコードは、10進数でかつ任意の自然数を2進数に変換してその計算結果をメッセージボックスに出力するもの。変換のための計算にDo Loop While構文を使っている。
REM ***** 10進数の自然数を2進数に変換 ***** REM 2147483648以上の値を入力すると REM オーバーフローが生じるので要注意 '変数を明示的に宣言して使う Option Explicit Sub Main '基数を定数として宣言 Const RADIX = 2 '使用する変数を宣言 Dim aNumber As Long Dim aDecimal As Long Dim aRemainder As Integer Dim strRemainder As String Dim strBinary As String '自然数を10進数で入力してもらい 'Int函数で小数点以下を切り捨てて代入 aNumber = Int(InputBox("2進数に変換したい" & _ "10進数の自然数を入力してください")) '入力された値が自然数であるかを検証 If aNumber < 1 Then MsgBox("無効な値です") 'Sub Mainを脱け出す Exit Sub End If '入力された値を条件式に使う変数に代入 aDecimal = aNumber '10進数を2進数に変換する計算ループ '10進数を基数で割った答えの整数部が0でない間繰り返す Do '10進数を基数で割って余りを代入 aRemainder = aDecimal MOD RADIX '余りをString型文字列に変換 strRemainder = CStr(aRemainder) '余りをString型文字列の先頭に随時追加 strBinary = strRemainder + strBinary '10進数を基数で割った答えの整数部を代入 aDecimal = Int(aDecimal / RADIX) Loop While aDecimal <> 0 '計算結果をメッセージボックスに出力 MsgBox aNumber & "を" & RADIX & _ "進数に変換すると" & strBinary & "になりました" End Sub
n進数のn(任意の自然数)は基数と呼ばれているが、この基数をまず定数として宣言。自然数の入力を促し、Int函数を用いてその値から小数点以下を切り捨てる。これをしないでLong型の変数に代入すると四捨五入されてしまうので。
次にIf構文を用い、入力された値が1未満、つまり自然数でなければ無効な値であることを伝えてSub Mainを脱け出す。
次に、入力された値を計算に使うための変数に代入しておく。こうしないと値が変わってしまうので。
そしてこのコードの核心、Do While Loop構文を使って10進数である自然数を2進数に変換するための計算を行う。10進数の自然数を2進数に変換するための計算式は、10進数の35を2進数に変換する計算を例にすると、次のとおり。
35 \div 2 = 17 \cdots 1 \\
17 \div 2 = 8 \cdots 1 \\
8 \div 2 = 4 \cdots 0 \\
4 \div 2 = 2 \cdots 0 \\
2 \div 2 = 1 \cdots 0 \\
1 \div 2 = 0 \cdots 1 \\
\Rightarrow 100011 \end{eqnarray} \]
与えられた10進自然数を答えが0になるまで2進数の基数で割ることを繰り返し、その余りを順に並べたものが計算結果の2進数となることがこの式から分かる。
上のコードのDo While Loop構文では、この計算を演算子MODを用いて余りを求める式と演算子/を用いた割り算の式とに分離して行っている。割り算の余りをString型の文字列に変換することで+演算子を使って右から左へと追加していく処理も同時に行っている。割り算の答えが0になると、Do While Loop構文の条件式を満たさなくなるので、このループから脱け出して計算は終了する。
そうして最後に計算結果をメッセージボックスに出力している。
Do Until Loop構文とDo Loop Until構文
Do Until Loop構文とDo Loop Until構文は、条件式が真になるまで処理内容を繰り返す。
Do Until Lopp構文は予め条件式の真偽を確認するが、Do Loop Until構文のほうは一度処理内容を実行してから条件式の真偽を確認する。そのため、前者は処理内容を一度も実行しない可能性があるのに対し、後者は処理内容を一度は必ず実行することになる。
Do Loop Until構文を使って上述のDo Loop While構文と同じ処理を実現すると次のようになるだろう。
'10進数を2進数に変換する計算ループ '10進数を基数で割った答えの整数部が0になるまで繰り返す Do '10進数を基数で割って余りを代入 aRemainder = aDecimal MOD RADIX '余りをString型文字列に変換 strRemainder = CStr(aRemainder) '余りをString型文字列の先頭に随時追加 strBinary = strRemainder + strBinary '10進数を基数で割った答えの整数部を代入 aDecimal = Int(aDecimal / RADIX) Loop While aDecimal = 0
Whileでは条件式の演算子が<>であったが、Untilではその演算子が=に変わっていることが分かる。Whileは文字通り「その間じゅう」だが、Untilは「それまで」。この条件式の例でいえば、Whileでは「0でない間じゅう処理を繰り返す」という意味となり、Untilでは「0になるまで処理を繰り返す」という意味になるから。
Exitステートメント
これらの繰り返し構文(ループ)は、Exitステートメントをその処理の中で指定することにより、繰り返しから途中で脱け出すことができる。例えば、繰り返し構文の中にIf構文を入れてその条件に合致した場合はそのループから脱け出す、という処理がExitステートメントによって可能になる。
サブルーチンから脱け出すときには脱け出したい箇所にExit Sub
というステートメントを置き、函数から脱け出すときには脱け出したい箇所にExit Function
というステートメントを置く。
For Next構文から脱け出すときには脱け出したい箇所にExit For
というステートメントを置き、Do Loop構文から脱け出すときには脱け出したい箇所にExit Do
というステートメントを置く。
次のコードは、5つの要素を持つ配列aを宣言していろいろなデータ型の値を代入し、その配列の要素をFor Next構文を用いて順番にメッセージボックスに出力してゆくのだが、ただしその繰り返しの中でその配列の要素がBoolean型だった場合にその時点でFor Next構文から直ちに脱け出すもの。If構文の中でExit Forステートメントを使っている。
REM ***** BASIC ***** '変数を明示的に宣言して使う Option Explicit Sub Main '配列を宣言そして代入 Dim a(1 To 5) As Variant a(1) = 5 a(2) = 2.7 a(3) = "abc" a(4) = "ABC" a(5) = False 'カウンター変数を宣言 Dim i As Integer '次の処理を5回繰り返す For i=1 To 5 'ただし配列の要素がBoolean型なら脱け出す If VarType(a(i)) = VarType(True) Then 'For構文の外に脱け出す Exit For End If '配列の要素をメッセージボックスに順に出力 MsgBox a(i) Next End Sub
配列の要素a(5)にはFalseというBoolean型の値が代入されているので、If構文の条件式を満たし、Exit Forステートメントが実行される。そのため、最後のFalseはメッセージボックスに出力されずに終わる、という仕掛け。データ型を検出するためにVarType函数を用いている。
この他にWhile Wend構文という繰り返し構文の一種があるが、Exitステートメントが無効であるなどの制約のためか、ほとんど使われていないらしい。
libreoffice basic機能全般をこれだけ体系的に書かれているものはあまり無いのでとても重宝しています。
返信削除多分利用者が少ないからでしょうが この充実した内容で「なぜコメントが0件? 」って思っています。
ありがとうございます。
返信削除