【初心者向け】動かして学ぶExcel VBA入門(11)

Excel VBA

こんにちは。ECF Tech担当
Michiharu.Tです。

Excel VBA入門の第11回です。
今回はエラーとその対応方法に関する内容です。エラーとは、プログラムの予期せぬ動作のことを指します。エラーを適切に処理するプログラムを書くことで、利用者にとって使いやすいプログラムを書くことができます。

本連載の目次は下記よりご覧頂けます。

【初心者向け】動かして学ぶExcel VBA入門
Excel VBAを動かしながら学べる連載をお送りしています。講座目次第1回 Excel VBAを始めようExcel VBAとはExcelマクロを動かしてみようExcelマクロの保存第2回 基本操作(1)セルに値を設定セルの削除オブジェクト...

コンパイルエラーと実行時エラー

Excel VBAにはコンパイルエラー実行時エラーの大きく2種類があります。

コンパイルエラー

コンパイルは、コンピュータがプログラムを解釈する作業のことです。コンパイルエラーはその際に発生するエラーで、文法の誤りが主な原因です。プログラムを修正することで、エラーが発生しないようにすることができます。

コンパイルエラー

上図のエラーは、値を代入しようとしている変数Nameが宣言されていないため、エラーとなっています。

実行時エラー

実行時エラーはプログラムの記述はあっているものの、実行中に発生してしまうエラーのことです。次のようなシンプルなマクロで確認してみましょう。

Sub tashizan()
    Dim val1 As Integer
    Dim val2 As Integer

    'A1とC1の値を取得
    val1 = Range("A1").Value
    val2 = Range("C1").Value

    '足し算の結果をE1に出力
    Range("E1").Value = val1 + val2
End Sub

上のマクロは下図のようなExcelシートにおいて、A1とC1のセルに数値を入力したら、その加算結果をE1に出力してくれるというものです。

足し算マクロ用シート

利用者がA1とC1のセルに正しく数値を入力すれば、プログラムは正常に動作しますが、数値以外(下図では「A」)の値を入力すると次のような結果となります。

実行時エラー

実行時エラーが表示されています。このエラーは整数(Integer)型の変数val2にC1セルの値を代入する際、C1セルの値が数値では無いために発生しています。実行時エラーは実際に動作させてみて、その状況に応じて発生するエラーです。この実行時エラーも適切に対処することで、より利便性が高く利用者に優しいプログラムを作成することができます。

実行時エラーに対する考え方

実行時エラーが起こりうる状況に対し、どのように対応すべきか。については大きく2つの考え方があります。足し算マクロを例に、それぞれの考え方でプログラムを修正してみましょう。

実行時エラーの発生を防ぐ

1つ目の考え方は、実行時エラーが発生しないようにプログラムを記述することです。先ほどの足し算プログラムにおける実行時エラーの原因は、val1 = Range("A1").Valueのような処理で、セルの値を無条件に変数に代入しようとしていることです。セルに入力される値が数値とみなせるかわからない点が問題です。

そこで対応策として、A1セルの値の内容を事前にチェックしたいと思います。VBAには値の種類を事前にチェックできる次のような関数が用意されています。

関数名 説明
IsEmpty 指定された値が空ならTrueを返す
IsNumeric 指定された値が数値ならTrueを返す
IsDate 指定された値が日付形式ならTrueを返す

これらの関数はいずれも引数を1つとり、その引数の値を対象に判定を行います。簡単なプログラム例でみてみましょう。

Sub isSample()
    If IsNumeric(5) Then
        MsgBox "数値です"
    End If
End Sub

このプログラムではIsNumeric関数を使って、引数に指定した値が数値かどうかを判定しています。引数には5が指定されています。5は数値とみなせるので、IsNumeric(5)の結果はTrueとなります。If文は条件式に指定した式がTrueならIf文内の処理に入りますので、MsgBox "数値です"が実行されることになります。実行結果は次のとおりです。

isSample実行結果

一方、下のプログラムではIsNumeric関数の引数に文字が入っており、数値と判定されないためFalseとなります。したがってIf文の処理に入らず、実行しても何も表示されません。

Sub isSample2()
    If IsNumeric("A") Then
        MsgBox "数値です"
    End If
End Sub

では次に、このIsNumeric関数を使って、最初の足し算プログラムを改良してみましょう。

Sub tashizan()
    Dim val1 As Integer
    Dim val2 As Integer

    'A1が数値でないなら処理を終了
    If Not IsNumeric(Range("A1").Value) Then
        Exit Sub
    End If

    'C1が数値でないなら処理を終了
    If Not IsNumeric(Range("C1").Value) Then
        Exit Sub
    End If

    'A1とC1の値を取得
    val1 = Range("A1").Value
    val2 = Range("C1").Value

    '足し算の結果をE1に出力
    Range("E1").Value = val1 + val2
End Sub

A1セルとC1セルに対する下のような処理が追加されています。

If Not IsNumeric(Range("A1").Value) Then
    Exit Sub
End If

上の例では、IsNumeric関数を使ってA1セルの値が数値かどうかを判定しています。Not演算子は条件式などの前に置かれ、「TrueFalseFalseTrueにする」演算子です。今回のIf文では「A1セルの値が数値でない場合」、つまりIsNumeric(Range("A1").Value)Falseの場合にIf文に入りたいので、Notを付けることでIsNumeric関数の結果がFalseの場合に条件式がTrueとなるようにし、If文に入るようにしています。

If文内のExit Subは、Subプロシージャの処理を途中終了させる役割があります。つまり、A1セルの値が数値でない場合は以降の処理はしない。というプログラムになります。その後C1セルについても下記のように同様の処理を行っています。

If Not IsNumeric(Range("C1").Value) Then
    Exit Sub
End If

これらの追加処理によって、2つのセルが数値であることを確認できたら、足し算処理のつづきを行っています。これで実行時エラーの発生を防ぐことができます。

If Not IsNumeric(Range("A1").Value) Thenは、実は「A1が数値である」の判定として十分とは言えません。理由は、IsNumeric関数が空の値に対し、Trueを返してしまうからです。したがってA1セルが空の状態で実行すると、If文に入らずに実行時エラーを発生させる恐れがあります。そのため、If文の条件式は「A1セルが空である または A1セルが数値でない」のいずれかに該当する場合にTrueとなるようにする必要があります。そのため、正確にはIsEmpty(Range("A1").Value Or Not IsNumeric(Range("A1").Value))とする必要があります。式が複雑だと感じる方は、次の実行時エラー発生時に対処する方法を検討しても良いでしょう。

実行時エラー発生時に対処する

実行時エラーに対するもう1つの考え方は、実行時エラーが発生したときに対処する方法です。On Errorステートメントを使用することで実現できます。

On Errorステートメントの基本的な文法は次のようになります。

On Error GoTo ラベル名
    :
ラベル名:
    'ここに実行時エラーの時の処理を書く

簡単に説明すると、On Error GoTo ラベル名以降の処理で実行時エラーが発生した場合は、ラベル名:の部分に処理がジャンプします。足し算マクロの例で具体的に確認します。

Sub tashizan()
    Dim val1 As Integer
    Dim val2 As Integer

    On Error GoTo DispMsg

    'A1とC1の値を取得
    val1 = Range("A1").Value
    val2 = Range("C1").Value

    '足し算の結果をE1に出力
    Range("E1").Value = val1 + val2

    Exit Sub

DispMsg:
    MsgBox "A1とC1には数値を入れてください"

End Sub

On Error GoTo DispMsgの部分と下記の処理が追加されています。ラベル名は自由に設定できるので、今回はDispMsgとしました。

DispMsg:
    MsgBox "A1とC1には数値を入れてください"

どのような動作をするかは、下の図でイメージして頂くと良いでしょう。

OnErrorのイメージ

On Error GoTo DispMsgより後の処理、つまり図の①に示す範囲で実行時エラーが発生すると、②の矢印が指すDispMsgのラベルに処理がジャンプし、「A1とC1には数値を入れてください」のメッセージを表示します。

実行時エラーが発生しない場合は、図の③に示すExit SubでSubプロシージャが終了します。このExit Subが無いと、実行時エラーが発生しない場合でもMsgBox "A1とC1には数値を入れてください"が実行されてしまうので注意が必要です。

ラベルはジャンプ先を示す単なる目印です。If文のように分岐を実現するわけではありません。そのため、今回のプログラムのようにExit Subをつけておかないと、処理がひたすら下に進み、MsgBox "A1とC1には数値を入れてください"まで実行されてしまいます。

複数の実行時エラーの処理

次にOn Errorステートメントを使って、複数の実行時エラーを処理するプログラムをご紹介します。

割り算シート

足し算プログラムと同様に、上図のようなシートで割り算を行うプログラム例です。A1とC1のセルに値を入れると割り算を行い、結果をE1セルに代入します。割り算を伴うプログラムの場合、0で割ってしまう処理にならないよう注意が必要です。割る数を0にして割り算をしてしまうと、下のような実行時エラーが発生します。

0で割り算

したがって、割り算プログラムを作るにあたっては

  • 整数型の変数に数値でない値を代入する実行時エラー(以降、型不一致エラーと記載)
  • 0で割り算をする実行時エラー(以降、0割りエラーと記載)

の2つに対応する必要があります。

それでは、プログラムを示します。

Sub warizan()
    Dim val1 As Integer
    Dim val2 As Integer

    On Error GoTo TypeError

    'A1とC1の値を取得
    val1 = Range("A1").Value
    val2 = Range("C1").Value

    On Error GoTo Div0Error

    '割り算の結果をE1に出力
    Range("E1").Value = val1 / val2
    Exit Sub

TypeError:
    MsgBox "A1とC1には数値を入れてください"
    Exit Sub

Div0Error:
    MsgBox "割る数に0は使えません"

End Sub

2つのOn Errorステートメントを使って、複数の実行時エラーを処理しています。こちらも下図で処理イメージを確認して頂くと良いでしょう。

実行時エラー処理

型不一致エラーに関連する処理はオレンジ、0割りエラーに関する処理は水色で示しています。

①で示す範囲で起こりうるのは型不一致エラーになりますので、その場合はTypeError:ラベルにジャンプ(図中②)し、「A1とC1には数値を入れてください」を表示します。

③で示す範囲で起こりうるのは型不一致エラーになりますので、その場合はDiv0Error:ラベルにジャンプ(図中④)し、「割る数に0は使えません」を表示します。

このようにすることで、複数の実行時エラーに対応した処理を記述することができます。

本日はここまでとさせて頂きます。最後までお読みいただきありがとうございました。エラー処理の方法を身につけて、利用者に優しいプログラムの作成を目指しましょう。

タイトルとURLをコピーしました