【VBScript】多次元配列のデータを追加する

Windows PC

こんにちは、ふみです。みなさんは VBScript で配列を使うことがありますか?

VBScript を使っている方は VBA も使える人が多いと思いますが、VBA と同じ感覚で配列を使うと VBScript ではエラーになってしまうことがあると思います。

今回は VBScript の多次元配列のつくり方やデータを追加する方法について紹介します。

配列と次元数

配列

配列とは物(データ)を保管する容器のようなものです。配列のデータは配列を宣言したプロシージャ(またはファンクション)が終了するまで PC(パソコン)のメモリー上に一時保管されます。
配列は変数を配列として宣言した時や、変数に関数から配列の戻り値を代入した時に、サイズが設定されると同時に添字(インデックス)が割り当てられます。
配列の添字はデータを出し入れする時に使います。

配列をマンションやアパートに例えると、エントランスで部屋番号(添字)を入力すると部屋の人が応答(データを参照)するような感じです。

多次元配列のデータをまんじゅうに例える

多次元配列は配列データをさらに配列化したものです。
配列に代入されたデータを饅頭(まんじゅう)に例えてみます。

  • 1次元配列は横一列の細長い饅頭の箱。
  • 2次元配列は縦横2列以上になっている大きな饅頭の箱
  • 3次元配列は大きな饅頭の箱を縦に積み重ねて収納できる段ボール箱
  • 4次元配列は段ボール箱を横に並べてトラックに収納した状態
  • 5次元配列は横に並んだ段ボール箱を上に積み重ねてトラックに収納した状態
  • 6次元配列は段ボール箱を扉の手前まで一杯に積み込んだトラック
  • 7次元配列は段ボール箱を積んだトラックが駐車場で横に並んだ状態
  • 8次元配列は段ボール箱を積んだトラックが駐車場で縦横に並んだ状態
  • 9次元配列は段ボール箱を積んだトラックの駐車場が複数ある状態
  • ・・・

このように配列は上限なく次元を積み重ねることができます
この例の9次元配列は「第2駐車場の入り口から向かって2列目、左から3番に止まっているトラックに積んである、手前から2列目、1番下の段の左から3つ目の段ボール箱に入っている上から2つ目の箱の上から3列目、左から2列目の饅頭」というように指定すると饅頭(データ)が取り出せます。
VBScript の配列で表現すると「変数名(2, 2, 3, 2, 1, 3, 2, 3, 2)」となります。

9次元配列の例を見ると非常にややこしく感じてしまいますが、実際のプログラムで最も良く使う多次元配列は2次元配列で、多くても3次元配列で済む場合がほとんどです。

多次元配列の作成と次元の割り当て

次のように商品の名前と値段のデータがあったとします。

りんご = 150円、みかん = 50円、バナナ = 100円

これらは次の表のように2次元配列のデータにまとめることができます。

添字012
0りんごみかんバナナ
115050100

この表では縦の並びがデータの区分、横の並びが商品の種別になっています。

このデータをプログラムで配列化するには、2次元配列を宣言する前に、1番目の次元と2番目の次元に入れるデータの種類を決めなければなりません。
他の種類の商品が追加される可能性がある場合は、1番目の次元をデータの区分(0~1)、2番目の次元を商品の種別(0~2)にするのがベストです。
このように多次元配列では追加される可能性のある項目を最後の次元に割り当てるものと覚えておきましょう。(理由は後述)

2次元配列の宣言からデータの代入までを VBScript で記述すると次のようになります。

Dim strArray()
ReDim strArray(1, 2)

strArray(0, 0) = "りんご": strArray(1, 0) = "150"
strArray(0, 1) = "みかん": strArray(1, 1) = "50"
strArray(0, 2) = "バナナ": strArray(1, 2) = "100"

1次元配列をリサイズしてデータを追加する

プログラムを実行中に新しいデータを読み込むことにより、既存の配列をサイズを拡張して新しいデータを追加する必要になることが良くあります。
1次元配列にデータを追加する VBScript のプログラムは次のとおりです。

サンプルコード

Option Explicit
Dim strArray()
ReDim strArray(2)

strArray(0) = "りんご"
strArray(1) = "みかん"
strArray(2) = "バナナ"

MsgBox ConfirmationTextForArray1D(strArray), , "データ追加前の配列"

'データの追加
ReDim Preserve strArray(UBound(strArray) + 1)
strArray(UBound(strArray)) = "梨"

MsgBox ConfirmationTextForArray1D(strArray), , "データ追加後の配列"

WScript.Quit

'******************************************************************************
'処  理:1次元配列のデータをメッセージ表示用の文字列で返す
'
'戻 り 値:メッセージ表示用の文字列
'
'引  数:strArray1D - 1次元配列
'
'備  考:配列の要素数が表示させる個数の上限を超えた分は残りを省略
'
Function ConfirmationTextForArray1D(ByRef strArray1D)
    
    Dim intN, strTemp
    Const c_intI = 10 '表示させる個数の上限
    
    For intN = LBound(strArray1D) To UBound(strArray1D)
        If intN > LBound(strArray1D) Then
            strTemp = strTemp & vbCrLf '改行の追加
        End If
        If c_intI >= 1 And intN >= c_intI + LBound(strArray1D) Then '上限超過時
            strTemp = strTemp & "他" & UBound(strArray1D) - (c_intI - 1)
            Exit For
        Else
            strTemp = strTemp & "配列(" & intN & ") = " & strArray1D(intN)
        End If
    Next
    
    ConfirmationTextForArray1D = strTemp

End Function

上記のコードを Windows 10 のアクセサリから開いたメモ帳へコピー&ペースト後、文字コードを「ANSI」に設定し、適当なファイル名に拡張子「.vbs」をつけてデスクトップ等に保存すると、すぐに動作確認できます。
保存した vbsファイルをダブルクリックすると、配列のデータ追加前と追加後の内容がメッセージで表示されます。

解説

12行目の「ReDim Preserve ~」は新しいデータを追加するために、既存のデータをそのままに配列のサイズを拡張しています。
ReDim は Preserve を省略すると既存のデータは全て消去されます。

13行目は配列を拡張してできた空の要素に新しいデータ「梨」を代入しています。

19行目のアスタリスク(*)から下のファンクションは【VBScript】プロシージャとファンクション(関数)の使い方で紹介したファンクション(関数)をそのまま転用しています。

このファンクションは Excel等の VBAでも動作しますが、VBAで動作させる場合、戻り値、引数、変数、定数の型を「As ~」と記載したほうが良いです。VBA は引数の型が同じでないとエラーになります。

2次元配列をリサイズしてデータを追加する

2次元配列にデータを追加する VBScript のプログラムは次のとおりです。

サンプルコード

Option Explicit
Dim strArray()
ReDim strArray(1, 2)

strArray(0, 0) = "りんご": strArray(1, 0) = "150"
strArray(0, 1) = "みかん": strArray(1, 1) = "50"
strArray(0, 2) = "バナナ": strArray(1, 2) = "100"

MsgBox ConfirmationTextForArray2D(strArray, False, True), _
    , "データ追加前の配列"

'グレープフルーツのデータを追加する
ReDim Preserve strArray(1, UBound(strArray, 2) + 1)
strArray(0, UBound(strArray, 2)) = "梨"
strArray(1, UBound(strArray, 2)) = "120"

MsgBox ConfirmationTextForArray2D(strArray, False, True), _
    , "データ追加後の配列"

WScript.Quit

'******************************************************************************
'処  理:2次元配列のデータをメッセージ表示用の文字列に変換する
'
'戻 り 値:メッセージ表示用の文字列
'
'引  数:strArray2D - 2次元配列
'          boolCS - True = 列間をカンマ区切り、False = 列間をTab区切り
'          boolVertical - True = 2番目の次元を縦表示、False = 横表示
'
'備  考:配列の要素数が行列数の上限を超えた分は残りを省略
'
Function ConfirmationTextForArray2D(ByRef strArray2D, ByVal boolCS _
                                    , ByVal boolVertical)
    
    Dim intN1, intN2, strTemp, strSeparate, intD1, intD2
    Const c_intIy = 10 '行数の上限
    Const c_intIx = 10 '列数の上限
    
    If boolCS = True Then
        strSeparate = "," 'カンマ区切り
    Else
        strSeparate = Chr(9) 'Tab区切り
    End If
    If boolVertical = True Then
        intD1 = 1: intD2 = 2 '2番目の次元を縦表示にする変数設定
    Else
        intD1 = 2: intD2 = 1 '2番目の次元を横表示にする変数設定
    End If
    
    For intN2 = LBound(strArray2D, intD2) To UBound(strArray2D, intD2)
        If intN2 > LBound(strArray2D, intD2) Then
            strTemp = strTemp & vbCrLf '改行の追加
        End If
        If c_intIy >= 1 And intN2 >= c_intIy + LBound(strArray2D, intD2) Then
            strTemp = strTemp & "他" & UBound(strArray2D, intD2) _
                - (c_intIy - 1) & "行" '行数上限超過の処理
            Exit For
        End If
        For intN1 = LBound(strArray2D, intD1) To UBound(strArray2D, intD1)
            If intN1 > LBound(strArray2D, intD1) Then
                strTemp = strTemp & strSeparate '区切り文字の追加
            End If
            If c_intIx >= 1 _
                    And intN1 >= c_intIx + LBound(strArray2D, intD1) Then
                If intN2 = LBound(strArray2D, intD2) Then
                    strTemp = strTemp & "他" & UBound(strArray2D, intD1) _
                        - (c_intIx - 1) & "列" '列数上限超過の処理
                End If
                Exit For
            Else
                If boolVertical = True Then
                    strTemp = strTemp & "配列(" & intN1 & ", " & intN2 _
                        & ") = " & strArray2D(intN1, intN2)
                Else
                    strTemp = strTemp & "配列(" & intN2 & ", " & intN1 _
                        & ") = " & strArray2D(intN2, intN1)
                End If
            End If
        Next
    Next
    
    ConfirmationTextForArray2D = strTemp
    
End Function

上記のコードを Windows 10 のアクセサリから開いたメモ帳へコピー&ペースト後、文字コードを「ANSI」に設定し、適当なファイル名に拡張子「.vbs」をつけてデスクトップ等に保存すると、すぐに動作確認できます。
保存した vbsファイルをダブルクリックすると、配列のデータ追加前と追加後の内容がメッセージで表示されます。

解説

13行目の「ReDim Preserve ~」は新しいデータを追加するために、既存のデータをそのままに配列のサイズを拡張しています。
ReDim Preserve は 多次元配列の場合、最後の次元以外の次元の数字を変更するとエラーが発生します。その為、多次元配列では追加される可能性のある項目を最後の次元に割り当てる必要があります。

22行目のアスタリスクから下のファンクションは1次元配列で使ったファンクションを2次元配列用にアレンジしたものです。
引数の説明にも記載してありますが、2番目の引数を True に変更すると列間がカンマ区切りになり、3番目の引数を False に変更すると縦横が逆転します。

このファンクションは Excel等の VBAでも動作しますが、VBAで動作させる場合、戻り値、引数、変数、定数の型を「As ~」と記載したほうが良いです。VBA は引数の型が同じでないとエラーになります。
ちなみに、33~38行をVBA仕様で記述すると

Function ConfirmationTextForArray2D(ByRef strArray2D() As String _
        , ByVal boolCS As Boolean, ByVal boolVertical As Boolean) As String
    
    Dim intN1 As Integer, intN2 As Integer, strTemp As String
    Dim strSeparate As String, intD1 As Integer, intD2 As Integer
    Const c_intIy As Integer = 10 '行数の上限
    Const c_intIx As Integer = 10 '列数の上限

となります。

配列データの消去

データ量の多い配列はメモリーを占有して処理効率を悪くする可能性があるので、プログラムの途中で不要になったら消去しましょう。

配列は「Erase 配列名」で消去できます。
上記で使った配列strArray を消去する場合は

Erase strArray

となります。VBScript では変数名の後ろに()がついているとエラーが発生します。
VBA は変数名の後ろに()をつけてもエラーが発生しません。

まとめ

  • 配列は上限なく次元を積み重ねることができる
  • 多次元配列では追加される可能性がある項目を最後の次元に割り当てる
  • データ量の多い配列は不要になったら Erase で消去する

ありがとうございました。

コメント

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