« お前何年VBScript書いてんだって話なので | メイン | DVD → Windowsメディアサーバー »

2008年7月12日

VBScriptにおけるpushの決定版

VBScriptの配列は扱いづらいことで有名(?)ですが、pushを定義したらだいぶましになりました。以前から使っていたのだけど、改良を重ねてこれが決定版。

Sub push(arr,elm)
  Dim i,tmp : i = 0
    If IsArray(arr) Then
      For Each tmp In arr
        i = 1
        Exit For
      Next
      If i=1 Then
        Redim Preserve arr(Ubound(arr)+1)
      Else
        Redim arr(0)
      End If
    Else
      arr = Array(0)
    End If
    If IsObject(elm) Then
      Set arr(Ubound(arr)) = elm
    Else
      arr(Ubound(arr)) = elm
    End If
End Sub

実行コードサンプル

Dim hoge()
push hoge,"test"
push hoge,Array(1,2,"fuga",44)
Dim fuga : Set fuga = CreateObject("Scripting.Dictionary")
fuga("item1") = "testitem"
push hoge,fuga
WScript.Echo(hoge(0))
WScript.Echo(hoge(1)(3))
WScript.Echo(hoge(2)("item1"))

これで、配列にオブジェクトやら配列やらを突っ込めてフリーダムな感じ。ひゃっほー。配列にはオブジェクト格納できないのかと思ってたら、「Set」を使えばできるんだね。実はVBScriptでもかなり複雑なデータ構造が実現可能。Classも定義できるし。ちなみに、こうやって配列にオブジェクトを突っ込むと参照渡しになるようだ。配列だと値渡し。

配列関係の条件分岐が複雑になっているが、空の配列の定義方法によって挙動が異なるのが理由。

  1. Dim hoge : hoge = Array() →IsArray()はTrue。UBound()を使うと、-1が返る
  2. Dim hoge() →IsArray()はTrue。UBound()を使うと、即エラー(!)
  3. Dim hoge(-1) →こういう宣言は不可能(即エラー)

2の変数宣言の方法がシンプルで好きなのだが、こうすると型が形だけ配列扱いになるだけで、Uboundで配列の長さも取得できないというクソ仕様。なんで、コレクションを見に行って、ひとつでも要素があれば配列を伸ばすという形にした。

かなり無理やりなので、メモリはすげー無駄遣いしてるんだろうなぁ。Perlみたいに、無名ハッシュみたいなのを直接入れたり、深いデータ構造の自動生成とかは流石にさせられないのが残念。

それと、配列を走査して書き出したりしようと、オブジェクトを書き出そうとしたときにエラー吐いちゃうんだよね。オブジェクトにtoStringみたいなのを定義できない(多分)のが困る。

投稿者 Songmu : 2008年7月12日 16:11