Visual Basic 初級講座 [改訂版]
VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

第14回 繰り返し処理 Do ~ Loop

2020/6/14

この記事が対象とする製品・バージョン

VB2019 Visual Basic 2019 対象です。
VB2017 Visual Basic 2017 対象です。
VB2015 Visual Basic 2015 対象です。
VB2013 Visual Basic 2013 対象です。
VB2012 Visual Basic 2012 対象です。
VB2010 Visual Basic 2010 対象です。
VB2008 Visual Basic 2008 対象です。
VB2005 Visual Basic 2005 対象です。
VB.NET 2003 Visual Basic.NET 2003 対象外ですがほとんどの説明があてはまるので参考になります。
VB.NET 2002 Visual Basic.NET (2002) 対象外ですがほとんどの説明があてはまるので参考になります。
VB6対応 Visual Basic 6.0 × 対象外です。

 

目次

 

1.Do ~ Loopの概要

Do ~ Loop (読み方:Do=ドゥー、Loop=ループ) または While ~ End While(読み方:While=ワイル)を使うと、条件を満たすまで処理を繰り返すことができます。

VBの繰り返しの構文には、このほかに前回説明した For ~ Next と まだ説明していない For Each ~ Next があり、違いを簡単にまとめると次の通りです。

For ~ Next 回数を指定して処理を繰り返します。
Do ~ Loop 条件が達成されるまで処理を繰り返します。
While ~ End While Do ~ Loopとほぼ同じです。古い構文であり、あまり使用しません
For Each ~ Next コレクションや配列の要素ごとに繰り返します。

For Each ~ Nextについては別の回で詳しく説明します。

 

たとえば、次の例では無限にメッセージを表示します。MsgBoxはOKを押すまで次の命令を実行しないので、メッセージは1つずつ表示されます。実行しても画面がメッセージにあふれて操作できなくなるということはありません。

このプログラムを停止するにはVisual Studioの停止ボタンを押してください。

VB6 VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Do
    MsgBox("無限に表示しますよ。")
    MsgBox("停止するにはVisual Studioの停止ボタンを押してください。")
Loop

 

メモ メモ  -  なぜ2種類あるのか?

Do ~ Loop と While ~ End Whileは同じ機能です。厳密には、While ~ End WhileでできることはDo ~ Loopですべてできるので、While ~ End Whileはなくなっても困りません。

なぜ、同じような機能が2つあるのかはっきりしたことはわかりませんが、どうも歴史的な経緯のようです。BASIC言語におけるループはFor ~ Nextが最も古く、その次にWhile ~ Wend が登場し、その後 Do ~ Loop が登場したようです。(VB6の時代まではWhile ~ End WhileではなくWhile ~ Wend と記述していました。)

Do ~ Loopの登場をもってWhile ~ Wend は機能的には不要になったのですが、それまでWhile ~ Wendになれ親しんでいたプログラマーのために残しておいたということではないかと推測します。

どうも1990年頃には既にDo ~ Loopが登場していたようなので、あれから30年・・・。そろそろWhile ~ Wend (End While)はなくしてもいいように思います。

過去のBASIC While ~ Wend Do ~ Loop 出典
BASIC (1972年ごろ) なし? なし? Computing with the BASIC Language
N88-BASIC (1981年登場) あり なし N88-BASIC(86) 命令・関数一覧
IBM BASICA(1981年登場) あり なし QuickBASIC: the complete reference
Quick Basic(1990年ごろ) あり あり Microsoft QuickBASIC programmer's reference 抜粋1
Microsoft QuickBASIC programmer's reference 抜粋2

参考:While ~ Wend はBASICの遺物

https://stackoverflow.com/questions/32728334/do-while-loop-and-while-wend-loop-whats-the-difference

 

 

 

2.Do ~ Loopによる繰り返しの実践

2-1.CPUメーター

Do ~ Loopの構文を眺める前に、1つサンプルを作ってDo ~ Loopに慣れておきましょう。

実際に一緒に試してみることをお勧めします。

CPU使用率をリアルタイムに表示するアプリケーションを作って見ます。

新しいWindowsフォームアプリケーションを.NET Frameworkで作成し、プロジェクト名は CPUMeter としてください。

画面には左にLabel、右にPictureBoxを次のように配置します。右側の緑の棒はPictureBoxです。

CPUメーター デザイン画面

 

プロパティ設定は下記の通りです。

コントロール プロパティ 備考
フォーム Text CPUメーター  
  MaximizeBox False 最大化できなくします
  FormBoderStyle FixedSingle サイズ変更できなくします
Label (Name) lblCpu  
  Text -  
  Font Verdana サイズ 24  
PictureBox (Name) picCpu  
  BackColor LimeGreen  

 

2-2.CPU利用率の取得

CPU使用率を取得するには、PerformanceCounterクラスのNextValueメソッドを使用します。(読み方:PerformanceCount=パフォーマンスカウンター、NextValue=ネクストバリュー)。

この例をフォームの Shown イベントに記載してください。Shownイベントはフォームが表示された直後に発生します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown

    Dim cpuCounter As New PerformanceCounter("Processor", "% Processor Time", "_Total"))
    cpuCounter.NextValue() '1回目は必ず 0なので呼び出すだけで何もしない。

    '0.5秒間なにもしない
    Task.Delay(500).Wait()

    '0.5秒間の間に採取された値を取得
    Dim cpuValue As Integer = CInt((cpuCounter.NextValue())

    MsgBox("現在のCPU使用率は " & cpuValue.ToString & " %"))

    cpuCounter.Dispose()

End Sub

※Visual Studio 2005, 2008で実行する場合は、Task.Delayの行を Threading.Thread.Sleep(500) に置き換えてください。

PerformanceCounterクラスはWindowsのパフォーマンスカウンターの機能を利用してCPU使用率などさまざまな指標を取得できます。何を取得したいのかをコンストラクターの引数に指定します。

パフォーマンスカウンターは少し癖があって最初は必ず 0 を返します。その後、少し待機して再度値を取得すると、その待機していた間に観測された値を取得できます。

そのため上記の例では2回 NextValueを呼び出して、その間に1秒何もしない時間を挿入しています。指定した時間何もしない機能は Task.Delay.Wait で実現できます。Delayの引数には待機する時間をミリ秒で指定します。この例では500ミリ秒を指定しているので0.5秒待機します。

PerformanceCounterクラスは使い終わったらDisposeメソッド(読み方:Dispose=ディスポーズ)を呼び出すことがルールになっているので、呼び出しています。このメソッドはPerformanceCounterクラスが使用していたリソースを開放します。

この例を実行すると、直前0.5秒間のCPU使用率を表示することはできます。やってみてください。

操作方法 PerformanceCounterクラスのコンストラクターの引数に渡す値

PerformanceCounterクラスのコンストラクターで指定すべき値はWindowsのコントロールパネルからシステムとセキュリティー > 管理ツール > パフォーマンスモニターの カウンターの追加画面でわかります。

PerformanceCounterクラスのコンストラクターの値をパフォーマンスモニターで確認する

 

 

2-3.CPUを使用率をフォームに表示

この段階ではまだ1回値が表示されるだけですが、CPUメーターでは継続してCPU利用率を常に表示するようにしたいので、繰り返して処理を実行する必要があります。Do ~ Loopを使って繰り返すように改造してみましょう。

その前に、少しさきほどの例を改造して次のようにしてみてください。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown

    Using cpuCounter As New PerformanceCounter("Processor", "% Processor Time", "_Total"))
        cpuCounter.NextValue() '1回目は必ず 0なので呼び出すだけで何もしない。

        '0.5秒間なにもしない
        Task.Delay(500).Wait()

        '0.5秒間の間に採取された値を取得
        Dim cpuValue As Integer = CInt((cpuCounter.NextValue())

        picCpu.Width = cpuValue * 5
        lblCpu.Text = cpuValue.ToString

    End Using

End Sub

※Visual Studio 2005, 2008で実行する場合は、Task.Delayの行を Threading.Thread.Sleep(500) に置き換えてください。

ポイントは2つあります。1つは、Using ~ End Using という構造を追加した点です。PerformanceCounterクラスは使い終わったら必ずDisposeを呼ぶルールであるということは先ほど説明しましが、エラーが発生した場合のことなどを考えると『必ず』Disposeを呼ぶというのは結構難しく複雑なプログラムになってしまうのです。Using ~ End Usingは「必ずDisposeを呼ぶ」というだけの機能であり、これを使っておけば通常はDisposeの呼び出しのことは何も考える必要がなくなります。実際、書き換えた例ではDisposeの呼び出しは削除しました。自動的に呼び出してくれるようになるので不要なのです。わざわざ専用の構文が用意されていることからわかるように必ずDisposeを呼ぶというルールを持っているクラスはPerformanceCounterクラスの他にもたくさんあり、今後 Using ~ End Using をよく見かけるようになると思います。

2つ目のポイントはMsgBoxではなく、フォームに貼り付けたラベル(lblCpu)とピクチャーボックス(picCpu)でCPU使用率を表現するに変更した点です。ピクチャーボックスのサイズの計算はこの例では簡略に書いており、CPU使用率の5倍の幅になるようにしています。そのためCPU使用率が100%のとき、ピクチャーボックスの幅は 500ピクセルになります。

実行するとこのようになります。

CPUメーター

 

2-4.CPU使用率をリアルタイムに表示

それでは、Do ~ Loop を使用して、繰り返し実行するようにしてみましょう。

Do ~ Loop で挟んだ箇所が繰り返して実行されます。どこを挟めばよいでしょうか。次のようになります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown

    Using cpuCounter As New PerformanceCounter("Processor", "% Processor Time", "_Total")
        cpuCounter.NextValue() '1回目は必ず 0なので呼び出すだけで何もしない。

        Do
            '0.5秒間なにもしない
            Task.Delay(500).Wait()

            '0.5秒間の間に採取された値を取得
            Dim cpuValue As Integer = CInt(cpuCounter.NextValue())

            picCpu.Width = cpuValue * 5
            lblCpu.Text = cpuValue.ToString

            Application.DoEvents
        Loop
    End Using

End Sub

※Visual Studio 2005, 2008で実行する場合は、Task.Delayの行を Threading.Thread.Sleep(500) に置き換えてください。

この例は、実行すると終了できないという問題があるのですが、Visual Studioの停止ボタンをクリックして終了させることができるのでとりあえず大丈夫です。実行するとちゃんとCPU使用率の変化に応じて画面が変わっていくのが確認できます。CPU使用率に変化をつけたい場合は、CNNのWebサイトを開いたり、Visual Studioをもう1つ起動するなど、CPUを使いそうな操作をしてみてください。

この例では Loop の直前で Application.DoEventsメソッド (読み方:Application=アプリケーション、DoEvents=ドゥーイベンツ)を呼び出しています。

このプログラムだとDo ~ Loop が無限に繰り返されるため、Shownイベントが終わらないのです。イベントが終わらないとそのイベント内で指示している画面の更新(この場合、lblCpuとpicCpuの更新)は実際の画面にはなかなか反映されません。Application.DoEventsメソッドを呼び出すとそのときまでにたまっていた画面の更新処理などを処理してくれるのでイベントが終わらなくても画面が更新されるというわけです。一般的にApplication.DoEventsに頼らないといけない構造はあまり良い構造ではないのですが、今回はDo ~ Loop を説明したかったので少し目をつむります。

メモ メモ  -  CPU使用率

ある瞬間 CPU は使用されているか使用されていないかのどちらかで、50%使用されている、20%使用されているなどの中間の状態は存在しません。

CPU使用率とは、CPUが使用されているか・されていないかを 何回かチェックした結果、そのうちどのくらいが使用されていない状態だったかを示す割合を100から引いた値です。たとえば、100回チェックして、70回はCPUが使用されていなかったとすると、CPU使用率は30%です。 こういうわけなので、CPU使用率には、どのくらいの間隔をあけて測定したかが重要です。この間隔はサンプリング間隔と呼びます。サンプリング間隔が数秒など長い場合、そのうち1秒でものすごい処理をしていても結果としてのCPU使用率は低く算出されます。短い場合は偏った値が算出されるかもしれません。

同じマシンのCPU使用率を測定していてもサンプリング間隔によって結果は異なります。そのため、ここで作るサンプルと、Windowsに付属のタスクマネージャーなどで見た数値は異なっていても正常です。

性能テストやパフォーマンステストを行うテスト担当者はCPU使用率を評価する際には個々の数値に惑わされないようにご注意ください。長期間高い割合をキープすることは問題ですが、断続的に高い割合を示す場合は測定方法による数値のマジックであり問題ない場合もあります。

 

 

2-5.ループに条件をつける

実行してフォームの右上の×ボタンを押すと、フォームは見えなくなりますが、Do ~ Loopは動作をし続けます。Visual Studioを確認すると、フォームが見えなくなった後も停止ボタンが押せる状態になっており、プログラムが動作を続けていることが確認できます。

Do ~ Loop は条件が満たされるまで処理を繰り返す機能なので終了する条件を指定することが簡単にできます。今回は、フォームが見えなくなったら処理を中止することにしましょう。フォームのVisibleプロパティ(読み方:Visible = ビジブル)はフォームが表示されている場合はTrue、非表示の場合は False になるのでこの条件に使用できます。

Do の後ろに「While 条件」を記述すると、その条件がTrueの間はループを継続し、Falseの場合はループを終了するという意味になります。

そのため修正版のプログラムは次のようになります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown

    Using cpuCounter As New PerformanceCounter("Processor", "% Processor Time", "_Total")
        cpuCounter.NextValue() '1回目は必ず 0なので呼び出すだけで何もしない。

        Do While Me.Visible
            '0.5秒間なにもしない
            Task.Delay(500).Wait()

            '0.5秒間の間に採取された値を取得
            Dim cpuValue As Integer = CInt(cpuCounter.NextValue())

            picCpu.Width = cpuValue * 5
            lblCpu.Text = cpuValue.ToString

            Application.DoEvents
        Loop
    End Using

End Sub

※Visual Studio 2005, 2008で実行する場合は、Task.Delayの行を Threading.Thread.Sleep(500) に置き換えてください。

なお、フォームが何か別のウィンドウの裏に隠れてユーザーの目から見えないだけの状態はVisibleはTrueです。今回のように×ボタンを押してフォームを閉じた場合などにVisibleはFalseになります。

 

2-6.Timerバージョン

大分それっぽいプログラムができましたが、Do ~ Loopの説明がしたかったので少し強引な作りになってしまいました。CPUメーターのようなものをWindowsフォームアプリケーションで本格的に作りたい場合はTimerコンポーネントを使用するほうが本来は適切です。今回使用したPerformanceCounterクラスはCPU使用率の他にもさまざまな指標を取得できるので、なにか実用に役立てられるかもしれません。

Timerコンポーネントを使用する場合は、ツールボックスからフォームに貼り付けて(Timerはコンポーネントなのでフォームに貼り付けると、フォームの下の領域に表示されます)、プロパティウィンドウでIntervalプロパティを500、EnabledプロパティをTrueにします。後は次のようにプログラムするだけです。

VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim cpuCounter As New PerformanceCounter("Processor", "% Processor Time", "_Total")
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    Dim cpuValue As Integer = CInt(cpuCounter.NextValue())

    picCpu.Width = cpuValue * 5
    lblCpu.Text = cpuValue.ToString

End Sub

プログラムが短い上にこっちの方が優秀で、フォームを最小化したときも問題なく動作します。実はDo ~ Loop版の方のプログラムは最小化すると動作がおかしくなってしまいます。

このようにFor ~ NextやDo ~ Loopの代わりに Timer を使うことでよくなる場合も多いです。

 

3.Do ~ Loop の書き方

3-1.構文

Do Loop構文をまとめると次の通りです。

赤い部分は必ず記述する必要があります。その他の部分、たとえば、条件 は必要があるときだけ記述します。

VB6 VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Do 条件

     繰り返して実行する処理

Loop 条件

条件を省略した場合、Do ~ Loop の構文上は無限にループします。別途、ReturnやExit Doなどを使ってループを終わらせることはできます。

条件を記述する場合は、Doの行またはLoopの行に記述します。両方に記述することはできます。どちらに記述したかで条件が評価されるタイミングが変わります。

コードスニペットは4種類用意されており、キーボードのショートカットは DoUntil[TAB]やDoWhile[TAB]です。

 

3-2.条件 While と Until

条件は While 条件式 または Until 条件式 と記述します。(読み方:Until=アンティル)

条件式はIf文の条件式と同じでTrueまたはFalseを返すものであればなんでも指定できます。

While 条件式 の場合、その条件式が True の場合は、ループを継続します。

Until 条件式の場合、その条件式が True になるまで、ループを継続します。つまり、Trueになるとループを終了します。

そういうわけでWhileとUntilはループの継続条件が逆になります。

Whileの例を示します。

この例では条件をループの先頭、Do の行に記述しているため、条件の評価はループの先頭で行われます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim i As Integer

Do While i < 5
    i += 1
    Debug.Print(i.ToString)
Loop

この例は i が 5より小さい場合、ループを継続します。

実行すると出力ウィンドウのデバッグには次の通り出力されます。

1
2
3
4
5

この例では条件の評価はループの先頭で行われるので、 i が 5 になった瞬間にループが自動的に終了するわけではなく、i が 5以上になった状態でループの先頭が実行されるとループが終了します。

そのため、「5」も出力されています。

ブレークポイントを設定して、1行ずつステップ実行するとどのように実行されているのかよくわかります。

Do Loopのステップ実行

この動画の下側に表示されいる変数 i の値を確認するためのウィンドウはウォッチウィンドウです。ウォッチウィンドウは自分で指定した値を逐次確認することができます。実行中に[デバッグ]メニューの[ウィンドウ]-[ウォッチ]から表示できます。全部で4つあり、好きに使い分けできます。ウォッチウィンドウに監視したい変数をプログラムからドラッグ&ドロップするか、直接ウォッチウィンドウに変数名等を入力することで監視できます。不要になったら、クリックしてDeleteキーを押して削除できます。

 

条件を下のLoopに記述すると条件の評価はループの一番下で実行されます。そのため、はじめから条件に合致しない場合でもとりあえず1回は処理が実行されることになります。

その例を示します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim isTest As Boolean = False

Do
    Debug.Print(Now.ToString("HH:mm:ss"))
Loop While isTest

この例では条件であるisTestははじめから False ですが、条件を評価するのが Loop の行のため、処理が1回だけ実行され、デバッグウィンドウの出力にシステム時刻を出力します。

 

Utilは条件の判定が逆になるだけで、使い方はWhileでの条件指定と同じです。

Whileでも条件に Not をつけると Until と同じになるのでWhileとUntilのどちらか1つはなくなっても機能上は困らないです。使いやすいと思ったほうを使ってください。

参考に Until の例も1つ紹介します。

この例は i が 5 になるまで処理を繰り返します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim i As Integer

Do Until i = 5
    i += 1
    Debug.Print(i.ToString)
Loop

 

3-3.Exit Do

Exit Doを使うと、ループをすぐに終了できます。通常は If などで独自の条件判断を行ったうえで Exit Do します。

次の例は、ユーザーが「いいえ」を選択するとループを終了します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Do
    Dim answer As MsgBoxResult
    answer = MsgBox("まだ続けますか?", vbYesNo Or vbQuestion)

    If answer = vbNo Then
        Exit Do
    End If
Loop

この例はメッセージボックスで「いいえ」をクリックするとExit Doが実行され、ループを抜け出します。

その他にWhileやUntilでの条件が記載されていないので「いいえ」をクリックするまで無限でループを繰り返します。

 

 

VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

For i As Integer = 9 To 0 Step -1
    '繰り返して実行する処理
Next

この手法はFor ~ Nextを使って何かの集合を1つずつ削除していく場合に使われることがあります。

この使い方は役に立つ例を見てみないとピンと来ないと思うので、とりあえず今は必要であればカウントダウンもできるということだけ覚えておいてください。

 

3-4.Continue Do

Continue Doを使うと、その周の実行を飛ばして次の周を実行します。

ひらがなで構成されるランダムな文字列を作成するプログラムを使って実例を見てみましょう。

Unicodeのコードポイントから文字を生成するにはChar.ConvertFromUtf32メソッド(読み方:ConvertFromUtf32=コンバートフロムユーティーエフさんじゅうに)を使用します。

たとえば「学」のUnicodeのコードポイントは、23398 です。文字の世界は16進数で表現することが多いので、16進数で表現すると &H5B66 です。「&H」 はVBで、それが16進数であることを示す目印です。

メモ メモ  -  Unicodeのコードポイント

UnicodeのコードポイントとはUnicodeの文字コードのことなんですが、「文字コード」という言葉は2つの意味で使われることがあり、混乱する場合があるので、Unicodeの文字コードについて語る場合は「コードポイント」という言葉を使います。Unicodeは1文字1文字にコードポイントが割り当てられています。

ところが、Unicodeで定義されている文字を数値で表現するときに、コードポイントで表現するのではなく、コードポイントとは別の数字に変換して表現する場合があります。なんで、そんなわかりにくいことをするのかというとたとえば、Unicode以前の文字コードとの互換性のためです。互換性のある表現にしておけばUnicodeを扱えない環境でもアルファベットくらいは正しく表示することができたりするわけです。このような変換をエンコードと呼びます。エンコードにはUTF-8, UTF-16, UCS-2などいろいろな種類があります。このエンコードされた数値のことを「文字コード」と呼ぶ場合もあるため、文字コードという言葉は混乱を招きます。なお、UTF-32はUnicodeのコードポイントをそのまま使うエンコード方式です。なので実質的な「変換」は発生しません。

 

そのため、プログラムから次のようにして「学」という文字列を生成できます。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim manabu As String = Char.ConvertFromUtf32(&H5B66)
MsgBox(manabu) '「学」と表示されます。

 

ランダムな字を生成するためには文字コードの部分をランダムな数値に置き換えます。

ひらがなの文字コードはUnicodeでは、&H3041 ~ &H3096 なので、ランダムなひらがなを1文字生成するプログラムは次のようになります。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Const HiraganaStart As Integer = &H3041 'Unicodeで最初のひらがなのコードポイント
Const HiraganaEnd As Integer = &H3096 'Unicodeで最後のひらがなのコードポイント

Dim r As New Random
Dim moji As String = Char.ConvertFromUtf32(r.Next(HiraganaStart, HiraganaEnd + 1))

MsgBox(moji)

 

あとはループでランダムな文字を連携していけば、とりあえず完成なのですが、ちょっと問題があります。

ひらがなの範囲には小さい「ゃゅょ」が含まれているのですがランダムに生成すると「かゅ」など読めない組み合わせが作成されてしまうかもしれません。「きゅ」なら読めます。

そこでループの中で「ゃゅょ」が生成された場合は、その直前の字が「きしちにひみりぎじびぴ」のどれかでない場合は採用しないというプログラムにしてみます。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Const HiraganaStart As Integer = &H3041 'Unicodeで最初のひらがなのコードポイント
Const HiraganaEnd As Integer = &H3096 'Unicodeで最後のひらがなのコードポイント

Dim r As New Random
Dim result As String = ""

Do
    Dim moji As String = Char.ConvertFromUtf32(r.Next(HiraganaStart, HiraganaEnd + 1))

    If moji Like "[ゃゅょ]" AndAlso Not (result.LastOrDefault Like "[きしちにひみりぎじびぴ]") Then
        Continue Do
    End If

    result &= moji
Loop Until Len(result) = 100


MsgBox(result)

※VB2005の場合 LastOrDefaultが使用できないので、この例は実行できません。

 「ゃゅょ」が生成された場合のIf文で前の文字が「きしちにひみりぎじびぴ」でない場合はContinue Forすることにしてみました。

そうでない場合は result の末尾に moji を追加します。

一応おさらいしておくと、moji Like "[ゃゅょ]" は moji が "ゃ" か "ゅ" か "ょ" の場合Trueになります。Like と [ ] を組み合わせると、この中のどれか1文字という条件を簡単に表現できるので便利です。

100文字生成するまで処理を続けることにしたのでUntilで文字数が100になるまでという条件をつけました。

途中登場する result.LastOrDefault(読み方:LastOrDefault=ラストオアデフォルト)は最後の文字という意味になります。たとえば、"ABC".LastOrDefaultは"C"を表しています。ただ単に最後の文字を取得するだけなら Last というメソッドもあるのですが、ループの先頭でこの条件判断が実行された場合、まだresultには1文字も格納されていないので、Lastだとエラーになってしまいます。LastOrDefaultは1文字も存在しない場合は 文字コード0 の特殊な文字(vbNullChar) を返してくれてエラーにはならないという違いがあります。

メモ メモ  -  実はいろいろ問題はあります

この例だと小さい「ゃゅょ」の出現率が著しく低くなってしまいます。それに、他にも「ばぇ」など読みにくい組み合わせをどこまで許容するか、古いひらがなである「ゐ」「ゑ」を許容するか、先頭に拗音や「ん」を許容するか、あと単体の「ゔ」など。

とは言え、ランダムな文字列が欲しい場合は、読み方はどうでもいい場合がほとんどだと思うので、条件をつける必要はあまりないかもしれません。

 

4.While ~ End Whileとの組み合わせ

While ~ End Whileは冒頭で説明したように、昔のBASICの遺物であり、使用する価値はありません。機能としては Do While ~ Loop と同じです。

Exit Do, Continue Doの代わりにExit While, Continue Whileが使用できます。

Do ~ Loopと違って条件を省略することはできません。無限ループしたい場合はWhile True ~ End While と記述します。条件はかならず先頭(Whileの行)に記述します。

 

ちょっとだけ、役に立つ場合があるのは2重ループの場合です。たとえば、Do ~ Loop を二重に書いた場合、内側のDo ~ Loop で Exit DoやContinue Doを書くと、内側のDo ~ Loopに対しての命令ということになり、外側のDo ~ Loopを直接制御することはできません。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Do
    Do
        Continue Do '内側の Do ~ Loop を先頭から実行する。
        Exit Do '内側の Do ~ Loop を抜ける。
    Loop
Loop

外側のDo ~ Loopを巻き込んで制御したければGoToを使うしかありません。しかし、GoToは前回説明したように使用しないことが推奨されており、プログラムがわかりにくくなるのであまり使いたくないものです。

2重ループが必要なとき、どちらかのDo~LoopをWhile~End Whileに書き換えると、Exit Do,Exit While, Continue Do,Continue Whileという区別ができるようになるので内側のループも外側のループも直接制御できるようになります。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Do
    While True
        Continue While '内側の While ~ End While を先頭から実行する。
        Exit While '内側の While ~ End While を抜ける。
        Continue Do '外側の Do ~ Loop を先頭から実行する。
        Exit Do '外側の Do ~ Loop を抜ける。

    End While
Loop

所詮2重ループでしか使えない付け焼刃で、それほどわかりやすいわけではないので、これができるからと言ってお勧めするわけではありません。