見出し画像

VBA基礎1:変数・配列・辞書・オブジェクト

1.概要

 VBA基礎として変数・配列を紹介します。Excel VBAに関して様々な本・ブログがあるため本記事では自分の備忘録用まとめ記事となっております。

2.基礎知識

2-1.プロシージャ

 VBAで記載する処理をプロシージャと呼び、主に3種類あります。なお同じ変数名・プロシージャ名は使用できないため命名規則は各自注意が必要です。

【プロシージャ一覧】
Subプロシージャ:戻り値を持たない処理であり「マクロダイアログ」から呼び出して実行可能です。
Private Subプロシージャ:戻り値を持たない処理であり「マクロダイアログ」から呼び出しできません(裏側だけで処理させる用)。
Functionプロシージャ:戻り値を持つ処理であり通常のExcel内でも使用が可能です。

2-2.モジュール作成

 「Alt+F11」よりVBEを開いて標準モジュールを追加します。そのモジュール内にプロシージャを記載することでマクロを作成します。

3.変数

3-1.変数名の定義方法

 Pythonでも同じですが変数を見やすくし何を表しているのか(変数、定数、関数、クラスなど)を明確にすることは重要です。参考までに命名規則の記事は下記の通りです。

3-2.変数の型式および宣言(Dim)

 Pythonではデータ型を定義しませんが、Excelでは一般的に使用する変数は定義(宣言)します。定義方法は下記の通りです。もし変数後ろの"As <データ型>"を記載しない場合は自動でVariantとして定義されるため、記載しなくてもエラーにはなりません(VBAの省略可能な記述について)。

[IN]
Dim <変数名> As <データ型>

 データ型一覧は下記の通りです(【VBA基本】変数のデータ型一覧参照)。

 実際のところ変数は宣言しなくても使用可能ですがプロシージャの上に"Option Explicit"を記載すると宣言していない変数を使用できないようにする制限を追加できます。

[Sampleコード]
Option Explicit

Sub Test()
    Dim A As String
    
    A = "Hellow World"
    Debug.Print A

End Sub

[OUT]
Hellow World

3-3.変数の適用範囲

 VBAでは変数の宣言箇所・方法により適用範囲(使用できるエリア)が異なり、大きく分けて3つあります(詳細は下記記事参照)。

【変数の適用範囲】
1.プロシージャ内だけで使用可(Sub()―End Subの間のみ)
2.モジュール内だけで使用可(同じモジュール内はどこでも使用可)
3.全モジュールで使用可:Public変数

4.配列:List

 配列とはPythonのList型のように複数の値を格納できる変数です。配列の作成方法および値の抽出方法を紹介します。

4-1.配列の作成1:配列の定義

 記載方法はPythonとは異なり要素ごとに値を代入していきます。注意点としては下記の通りです。

[記法1:要素数のみ指定]
Dim <変数名>(配列の最大index)

<変数名>(要素番号) = 指定要素数の値

[記法2:要素数の最小値・最大値を指定]
Dim <変数名>(Min to Max)

<変数名>(要素番号) = 指定要素数の値

[記法3:動的配列]
Dim <変数名>()

Redim <変数名>(指定したい要素数)

【配列の注意点】
●要素数のみ指定した場合は開始要素数は0 (1からではない)
●配列は0~最大indexのため、実際の要素数は指定値+1となる。
●配列宣言後に要素数を変更する場合は動的配列を使用してRedimで更新する

 サンプルコードは下記の通りです。

[IN]
Sub Test1()
    Dim Weekdays(4)
    
    Weekdays(0) = "Monday"
    Weekdays(1) = "Tuesday"
    Weekdays(2) = "Wednesday"
    Weekdays(3) = "Thursday"
    Weekdays(4) = "Friday"

    Debug.Print Weekdays(1) 'Tuesdayが出力
    
End Sub

[OUT]
Tuesday
[IN]
Sub Test2()
    Dim Weekdays(1 To 4) '配列の要素数を1から開始に変更
    
    '要素数0は存在しないため定義するとエラーとなる
    Weekdays(1) = "Tuesday"
    Weekdays(2) = "Wednesday"
    Weekdays(3) = "Thursday"
    Weekdays(4) = "Friday"

    Debug.Print Weekdays(0) '1開始にしているため要素数0だとエラーがでる
    
End Sub

[OUT]
実行時エラー'9':
インデックスが有効範囲にありません。
[IN]
Sub Test3()
    Dim Weekdays() '動的配列
    ReDim Weekdays(4) '配列の要素数を0~4に変更する
    
    Weekdays(0) = "Monday"
    Weekdays(1) = "Tuesday"
    Weekdays(2) = "Wednesday"
    Weekdays(3) = "Thursday"
    Weekdays(4) = "Friday"

    Debug.Print Weekdays(0)
    
End Sub
[OUT]
Monday

4-2.配列の作成2:Split関数を使用

 VBA関数で出力される値が配列であることを利用します。ここではsplit関数を使用して文字列を分割することで配列を作成しました。

[IN]
Option Explicit

Sub Test()
    Dim Weekdays_Str As String
    Dim Weekdays(4) '動的配列: Dim Weekdays ()はエラー※Weekdays() As String  ならOK
    
    Weekdays_Str = "Monday, Tuesday, Wednesday, Thursday, Friday"
    Weekdays = Split(Weekdays_Str, ",") '文字列を指定文字で分割

    Debug.Print Weekdays(0), Weekdays(4)
    
End Sub

[OUT]
Monday     Friday

4-3.配列数の確認:LBound/UBound関数

 配列数の確認はLBound関数とUBound関数を使用することで確認できます。配列でindexの開始/終了値を決めた場合はその値が出力されます。

[IN]
Sub Test()
    Dim Weekdays(4)
    
    Weekdays(0) = "Monday"
    Weekdays(1) = "Tuesday"
    Weekdays(2) = "Wednesday"
    Weekdays(3) = "Thursday"
    Weekdays(4) = "Friday"

    Debug.Print "LBound関数", LBound(Weekdays) '配列の最初のindex取得
    Debug.Print "UBound関数", UBound(Weekdays) '配列の最後のindex取得
    Debug.Print "配列数", UBound(Weekdays) - LBound(Weekdays) + 1 '配列数
    
End Sub

[OUT]
LBound関数   0 
UBound関数  4 
配列数      5 

4-4.配列のデータ抽出

 配列からデータ抽出する場合はindexを指定するか、L・UBound関数を使用してFor文でまとめて取得します。

[抽出方法1:個別に取得]
配列(index)

[抽出方法2:LBound/UBound関数を使用0]
    For i = LBound(配列) To UBound(配列)
        Debug.Print 配列(i) '全配列データをFOR文で出力
    Next
[IN]
Sub Test()
    Dim Weekdays(4)
    Dim i As Long
    
    Weekdays(0) = "Monday"
    Weekdays(1) = "Tuesday"
    Weekdays(2) = "Wednesday"
    Weekdays(3) = "Thursday"
    Weekdays(4) = "Friday"
    
    Debug.Print "Indexで抽出", Weekdays(0) 'index番号を指定
    
    For i = LBound(Weekdays) To UBound(Weekdays)
        Debug.Print Weekdays(i) '全配列データをFOR文で出力
    Next
    
End Sub

[OUT]
Indexで抽出  Monday

Monday
Tuesday
Wednesday
Thursday
Friday

5.辞書型:連想配列

 Pythonでいう辞書型データを作成する場合はDictionaryを使用します。

5-1.環境構築:Microsoft Scripting Runtime

 連想配列(Dictionary)を使用するには「ツール」->「参照設定」->「Microsoft Scripting Runtime」で選択しておきます。

「Microsoft Scripting Runtime」をチェックせずCreateObjectで「Scripting.Dictionary」を生成しても連想配列は使用できます。ただし参照設定しておくと自動補完機能が働くため設定しておくことを推奨します。

 なお、Dictionaryのメソッド・プロパティはそれぞれ下記の通りです。

5-2.辞書の作成1:Dictionaryの定義

 辞書を作成するためのDictionaryの定義方法は下記の通りです。

[辞書の定義方法1:参照設定で「Microsoft Scripting Runtime」選択済み]
Dim dict As New Dictionary
    
dict.Add <KEY>, <VALUE> 'Dictionaryオブジェクトの初期化、要素の追加
dict(<KEY>> = VALUE 'こちらの方法でもよい
[辞書の定義方法2:環境構築をしていない]
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
    
dict.Add <KEY>, <VALUE> 'Dictionaryオブジェクトの初期化、要素の追加

 サンプルコードは下記の通りです。

[IN]
Sub Test()
    Dim dict As Object
    Set dict = CreateObject("Scripting.Dictionary")
    
    dict.Add "BTC", 2992808
    dict.Add "ETH", 209926
    dict.Add "XRP", 47.845 '別パターンでデータ登録

End Sub

[OUT]
3

5-3.辞書の作成2:FOR文でシートから取得

 基本的には前節と同じであり、取得するデータをSheetから取得して辞書を作成しました。

[IN]
Sub Test2()
    Dim dict As Object
    Set dict = CreateObject("Scripting.Dictionary")
    
    'データを取得するシートをWithステートメントで指定
    With Worksheets("Sheet1")
        For i = 1 To 3
            Key = .Cells(i, 1).Value 'A列のデータ
            Value = .Cells(i, 2).Value 'B列のデータ
            dict.Add Key, Value '同じ行の{A列データ:B列データ}辞書を作成
        Next
    End With
    
    Debug.Print dict("BTC")

End Sub

[OUT]
2992808 

5-4.辞書のデータ確認

 辞書のデータ数、KEYの存在確認はそれぞれプロパティのCount, Existsを使用します。またFor Each構文を使用することで辞書のKEYをFOR文で取得できるため全データを確認できます。

[IN]
Sub Test3()
    Dim dict As Object
    Set dict = CreateObject("Scripting.Dictionary")
    
    dict.Add "BTC", 2992808
    dict.Add "ETH", 209926
    dict.Add "XRP", 47.845 '別パターンでデータ登録
    
    Debug.Print dict.Count
    Debug.Print dict.Exists("BTC"), dict.Exists("DOGE")
    
    For Each Key In dict
        Debug.Print "KEY", Key
        Debug.Print "VALUE", dict(Key)
    Next

End Sub

[OUT]
 3 
True      False
KEY      BTC
VALUE      2992808 
KEY      ETH
VALUE      209926 
KEY      XRP
VALUE      47.845 

5-5.辞書のデータ抽出

 辞書からのデータ抽出は"dict(<KEY>)"と記載します。サンプルは下記の通りです。

[IN]
Sub Test()
    Dim dict As Object
    Set dict = CreateObject("Scripting.Dictionary")
    
    dict.Add "BTC", 2992808
    dict.Add "ETH", 209926
    dict.Add "XRP", 47.845 '別パターンでデータ登録
    
    Debug.Print dict("BTC")
    Debug.Print dict("XRP")

End Sub

[OUT]
2992808 
47.845 

6.オブジェクト

 ブックやシートなどのオブジェクトを使用する場合は変数と定義方法が異なり、”Dim”ではなく”Set”を使用します。この時オブジェクト変数は絶対的な値は保持しておらず参照値となります。
 参照中はメモリを使用するため、メモリを解放するためにはSetにNothingを代入して参照を削除します。

[オブジェクトの定義方法]
Set <オブジェクト変数名> = オブジェクト変数

[オブジェクトの参照削除]
Set オブジェクト変数 = Nothing

 参考としてWorksheetオブジェクトを取得して、プロパティからシート名を取得します。

[IN]
Sub Test5()
    'Sheetオブジェクトを定義
    Set Sheet_1 = ThisWorkbook.Sheets("Sheet1") 'シート名から選択
    Set Sheet_2 = ThisWorkbook.Sheets(1) 'シートの順番から選択
    Set Sheet_3 = Sheet1 'シート名から選択
    
    Debug.Print Sheet_1.Name
    
End Sub

[OUT]
Sheet1

参考資料・参考記事

あとがき

 全部は書ききれないのでゆっくり更新予定


この記事が気に入ったらサポートをしてみませんか?