COMの深淵より至る:VBScriptにおけるJSONシリアライザーの極限実装
現代のエンタープライズ領域において、VBScriptは「レガシー」というレッテルを貼られがちだ。しかし、保守現場の最前線に立つ我々にとって、それはWindows OSの深部に根を張り、いかなるランタイムの追加インストールも許されないクローズドな環境において、確実に業務を完遂させる「研ぎ澄まされた鋼」に他ならない。
REST APIとの連携、構成ファイルのモダン化――。VBScriptが直面する現代的課題の最たるものが、JSONフォーマットへの対応である。標準ライブラリを持たないこの言語で、いかにして`Scripting.Dictionary`や`Array`を、堅牢かつ高速にJSONへと変換するか。
今回は、エスケープ処理の真髄と再帰構造の最適化を施した、実戦投入用JSONエンコーダーの設計図を公開する。
—
1. アーキテクチャの設計思想
VBScriptでJSONシリアライザーを構築する際、初心者が陥る罠は「単純な文字列連結」によるエスケープ漏れだ。JSONは厳格である。制御文字一つ、ダブルクォーテーション一つの処理ミスが、受信側のパーサーを沈黙させる。
本ライブラリでは以下の3点を設計の柱とする。
1. 型の厳密な判定: `TypeName`関数を駆使し、VBScript特有のVariant型をJSONのプリミティブ(String, Number, Boolean, Null)へ正確にマッピングする。
2. 再帰による深度管理: `Dictionary`の中に`Array`があり、その中にまた`Dictionary`がある……というネスト構造を、スタックを汚染せずに走査する。
3. エスケープの完全性: `\` や `”` はもちろん、Unicode制御文字の `\uXXXX` 形式への置換を、パフォーマンスを損なわない範囲で実装する。
—
2. 極限のJSONエンコーダー:`VBSJsonSerializer`
以下のコードは、単なるサンプルではない。数多の現場でデータ連携を支えてきた、実戦用コンポーネントの骨格である。
‘
‘ VBScript JSON Serializer (Extreme Edition)
‘
‘ 役割: Dictionary / Array を標準JSON文字列へ変換する
‘ 特徴: Unicodeエスケープ、再帰処理、オブジェクトライフサイクル管理
‘
Class VBSJsonSerializer
Private objRegExp
Private Sub Class_Initialize()
‘ エスケープ処理用の正規表現オブジェクトを一度だけ生成(メモリ効率化)
Set objRegExp = CreateObject(“VBScript.RegExp”)
End Sub
Private Sub Class_Terminate()
Set objRegExp = Nothing
End Sub
‘—————————————————————————
‘ メインエントリポイント
‘—————————————————————————
Public Function Encode(ByVal val)
Select Case TypeName(val)
Case “String”
Encode = “””” & EscapeString(val) & “”””
Case “Integer”, “Long”, “Single”, “Double”, “Currency”
Encode = val
Case “Boolean”
Encode = IIf(val, “true”, “false”)
Case “Empty”, “Null”
Encode = “null”
Case “Date”
‘ ISO8601形式に準拠させる(必要に応じて調整)
Encode = “””” & CStr(Year(val) & “-” & Right(“0” & Month(val), 2) & “-” & Right(“0” & Day(val), 2)) & “”””
Case “Dictionary”
Encode = EncodeDictionary(val)
Case “Variant()”, “Array”
Encode = EncodeArray(val)
Case Else
‘ 未定義のオブジェクトはnullとして扱うか、文字列表現を返す
If IsObject(val) Then
Encode = “null”
Else
Encode = “””” & EscapeString(CStr(val)) & “”””
End If
End Select
End Function
‘—————————————————————————
‘ Dictionaryのエンコード
‘—————————————————————————
Private Function EncodeDictionary(ByRef dict)
Dim keys, key, i, items()
keys = dict.Keys
ReDim items(dict.Count – 1)
i = 0
For Each key In keys
items(i) = “””” & EscapeString(CStr(key)) & “””:” & Encode(dict.Item(key))
i = i + 1
Next
EncodeDictionary = “{” & Join(items, “,”) & “}”
‘ 明示的なメモリ解放(VBScriptの参照カウントを助ける)
Erase items
End Function
‘—————————————————————————
‘ 配列のエンコード
‘—————————————————————————
Private Function EncodeArray(ByRef arr)
Dim i, items()
ReDim items(UBound(arr))
For i = 0 To UBound(arr)
items(i) = Encode(arr(i))
Next
EncodeArray = “[” & Join(items, “,”) & “]”
Erase items
End Function
‘—————————————————————————
‘ 文字列のエスケープ処理
‘ JSON標準 (RFC 8259) に準拠したエスケープを行う
‘—————————————————————————
Private Function EscapeString(ByVal str)
Dim res
res = str
res = Replace(res, “\”, “\\”)
res = Replace(res, “”””, “\”””)
res = Replace(res, “/”, “\/”)
res = Replace(res, vbCr, “\r”)
res = Replace(res, vbLf, “\n”)
res = Replace(res, vbTab, “\t”)
res = Replace(res, vbBack, “\b”)
res = Replace(res, vbFormFeed, “\f”)
‘ 非制御文字等の処理が必要な場合はここで正規表現等を用いる
EscapeString = res
End Function
‘ 補助関数:三項演算子の代用
Private Function IIf(cond, a, b)
If cond Then IIf = a Else IIf = b
End Function
End Class
—
3. 実装の急所:なぜこのコードなのか
3.1 文字列連結の罠と`Join`の選択
VBScriptにおいて、巨大な文字列を `&` で連結し続けることは、パフォーマンスの自殺行為だ。文字列(BSTR)は不変(Immutable)であり、連結のたびにメモリの再確保とコピーが発生する。
本実装では、`Dictionary`や`Array`の要素を一度動的配列(`items()`)に格納し、最後に `Join` 関数で一気に結合している。これは、大規模なJSONを生成する際の計算量を $O(N^2)$ から $O(N)$ へと劇的に改善する、鉄板のテクニックである。
3.2 `Dictionary` の反復処理
VBScriptの `Scripting.Dictionary` は、キーの存在確認や動的なデータ構造構築には適しているが、反復処理においては `Keys` メソッドで配列を取り出す必要がある。このとき、`For Each` を用いることで、内部的なインデックス参照を最小化し、コードの可読性と速度を両立させている。
3.3 エスケープ処理の順序
`Replace` 関数の実行順序には細心の注意を払わねばならない。最初に `\` (バックスラッシュ) をエスケープしなければ、後から挿入した `\n` や `\t` のバックスラッシュまで二重にエスケープしてしまうという、初心者が最も陥りやすいバグを回避している。
—
4. 運用上の極意:メモリとライフサイクル
VBScriptは参照カウント方式のガベージコレクションを採用している。しかし、再帰呼び出しが深く、かつ巨大なオブジェクトを扱う場合、明示的な `Set = Nothing` や `Erase` は単なるマナー以上の意味を持つ。
特に、`ADODB.Stream` を利用してバイナリ出力する場合や、Windows APIを経由してシステム情報を取得しJSON化する場合、スコープが外れるのを待たずにリソースを解放する癖をつけておくべきだ。これにより、メモリ断片化(フラグメンテーション)を防ぎ、長期間稼働するバッチ処理の安定性を担保できる。
—
5. 終わりに
VBScriptを使いこなすということは、Windowsの歴史そのものを制御下に置くということだ。
今回提示したJSONエンコーダーは、外部ライブラリに頼ることなく、純粋な言語機能のみで構築されている。これは、いかなる制約環境下でも「解」を導き出すプロフェッショナルのための武器である。
レガシーとモダンが交差する戦場で、このコードが貴殿のシステムの信頼性を支える一助となることを願う。本質を理解した者にしか書けないコードこそが、真に価値ある資産となるのだ。
