こんにちは!VBScriptの世界へようこそ。
業務自動化やレガシーなバッチ処理の現場において、VBScriptは今なお静かに、しかし強烈にインフラを支え続けている現役の言語です。
今回は、Web APIとの通信やクエリ文字列の構築で必ず直面する「URLエンコード(およびデコード)」をテーマに取り上げます。
「VBScriptでURLエンコードをしたいけれど、ネットで見つかるサンプルは独自関数で文字コード変換が複雑……」
「外部の怪しいDLLやCOMコンポーネントはセキュリティ上使えない……」
そんな悩みを一発で、しかもWindows標準機能だけで美しく解決する『MSXML2.DOMDocument の nodeTypedValue を利用した神ワザ』を伝授します。ここをクリアすれば、あなたのVBScriptのスキルは確実にワンランク上のエンジニア領域に到達しますよ。
—
なぜVBScriptでのURLエンコードは一筋縄ではいかないのか?
VBScript(というかWSH実行環境)には、JavaScriptの `encodeURIComponent` のような便利な標準関数が備わっていません。日本語などのマルチバイト文字をURLエンコード(UTF-8形式など)しようとすると、通常は以下のような面倒な処理が必要になります。
1. 文字列を1文字ずつ(あるいはバイト単位で)分解する。
2. 文字コード(Shift-JISやUTF-8)のバイナリ配列に変換する。
3. 1バイトずつ `%XX` の形式にHex変換して結合する。
「うわ、面倒くさそう……」と思いましたよね?
安心してください。WindowsのOS標準コンポーネントである `MSXML2.DOMDocument` を利用すれば、XMLのデータ型変換機能を巧みにハックして、たった数行でこの面倒な処理を爆速かつ安全に実行できるのです。
—
秘儀!DOMDocument + nodeTypedValue による実装コード
百聞は一見に如かず。まずは、現場でそのままコピペして使える完全なスクリプトを見てみましょう。メモ帳に貼り付けて拡張子を `.vbs` にすれば、すぐに実行できます。
‘ ==============================================================================
‘ スクリプト名: UrlCodecSample.vbs
‘ 概要: MSXML2.DOMDocument を利用した UTF-8 URLエンコード / デコード
‘ 執筆者: チーフアーキテクト
‘ ==============================================================================
Option Explicit
Dim targetText, encodedText, decodedText
targetText = “こんにちは、VBScriptの世界へ!”
‘ 1. エンコードの実行
encodedText = UrlEncode(targetText)
WScript.Echo “【エンコード結果】” & vbCrLf & encodedText
‘ 2. デコードの実行
decodedText = UrlDecode(encodedText)
WScript.Echo vbCrLf & “【デコード結果】” & vbCrLf & decodedText
‘ ——————————————————————————
‘ 関数名: UrlEncode
‘ 概要: 文字列を UTF-8 バイナリ経由で URL エンコードする
‘ ——————————————————————————
Function UrlEncode(strValue)
Dim i, c, ascCode, hexStr
Dim result
result = “”
‘ 1文字ずつ走査して安全な文字(アルファベット・数字など)以外を変換する
For i = 1 To Len(strValue)
c = Mid(strValue, i, 1)
ascCode = AscW(c)
‘ サロゲートペア(絵文字など)の簡易考慮
If ascCode < 0 Then ascCode = ascCode + 65536
' RFC 3986 に基づく安全な文字(A-Z, a-z, 0-9, -, _, ., ~)はそのまま通す
If (c >= “A” And c <= "Z") Or _
(c >= “a” And c <= "z") Or _
(c >= “0” And c <= "9") Or _
c = "-" Or c = "_" Or c = "." Or c = "~" Then
result = result & c
Else
' 日本語などのマルチバイト文字や記号は UTF-8 バイナリ化して %XX へ変換
result = result & Utf8EncodeChar(c)
End If
Next
UrlEncode = result
End Function
' ------------------------------------------------------------------------------
' 内部関数: Utf8EncodeChar
' 概要: 1文字を UTF-8 のバイト配列に変換し、%XX 形式の文字列を生成する神ワザ部分
' ------------------------------------------------------------------------------
Function Utf8EncodeChar(strChar)
Dim dom, node, stream
Dim bytes, i, hexByte, outStr
' DOMDocumentオブジェクトの生成
Set dom = CreateObject("MSXML2.DOMDocument.6.0")
Set node = dom.createElement("-")
' データ型を bin.hex(16進数バイナリ表現)に指定
node.dataType = "bin.hex"
' ★ここが本質:ADO Streamを使って文字を UTF-8 バイナリに変換する
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2 ' adTypeText
stream.Charset = "UTF-8"
stream.Open
stream.WriteText strChar
stream.Position = 0
stream.Type = 1 ' adTypeBinary
' DOMの nodeTypedValue にバイナリを流し込むことで、内部で型安全に保持させる
node.nodeTypedValue = stream.Read
stream.Close
Set stream = Nothing
' bin.hex形式で取得した文字列(例: "E38亾9...")を 2文字ずつ "%XX" に分割する
bytes = node.text
outStr = ""
For i = 1 To Len(bytes) Step 2
outStr = outStr & "%" & Mid(bytes, i, 2)
Next
Utf8EncodeChar = outStr
Set node = Nothing
Set dom = Nothing
End Function
' ------------------------------------------------------------------------------
' 関数名: UrlDecode
' 概要: %XX 形式の文字列を UTF-8 としてデコードする
' ------------------------------------------------------------------------------
Function UrlDecode(strValue)
Dim dom, node, stream
Dim i, hexChunk, bytes, decoded
' %XX 形式の文字列をバイナリ(bin.hex)形式の文字列に再構築
hexChunk = ""
i = 1
Do While i <= Len(strValue)
If Mid(strValue, i, 1) = "%" Then
hexChunk = hexChunk & Mid(strValue, i + 1, 2)
i = i + 3
Else
' 通常文字の場合は文字コードを16進数2バイト表現に直す
Dim ascCode, h1, h2
ascCode = AscW(Mid(strValue, i, 1))
If ascCode < 0 Then ascCode = ascCode + 65536
' 簡易的に1バイト文字とみなして処理(必要に応じて拡張可能)
hexChunk = Hex(ascCode)
If Len(hexChunk) < 2 Then hexChunk = "0" & hexChunk
i = i + 1
End If
Loop
On Error Resume Next
Set dom = CreateObject("MSXML2.DOMDocument.6.0")
Set node = dom.createElement("-")
node.dataType = "bin.hex"
node.text = hexChunk
' ADO Streamを使ってバイナリを UTF-8 文字列として読み出す
Set stream = CreateObject("ADODB.Stream")
stream.Type = 1 ' adTypeBinary
stream.Open
stream.Write node.nodeTypedValue
stream.Position = 0
stream.Type = 2 ' adTypeText
stream.Charset = "UTF-8"
decoded = stream.ReadText
stream.Close
Set stream = Nothing
Set node = Nothing
Set dom = Nothing
If Err.Number <> 0 Then
UrlDecode = strValue ‘ エラー時はフォールバック
Else
UrlDecode = decoded
End If
On Error GoTo 0
End Function
—
コードの深層解説:なぜこの方法が「最高峰」なのか?
このコードの肝は、`MSXML2.DOMDocument` の `nodeTypedValue` プロパティ と `ADODB.Stream` の華麗なる連携プレイにあります。
1. COMオブジェクトの適切な使い分け
- `MSXML2.DOMDocument.6.0`: XMLパーサですが、内部に強力なデータ型(XSDデータタイプ)の変換エンジンを持っています。`node.dataType = “bin.hex”` と宣言することで、XMLノードと16進数バイナリを自動的にバインドしてくれます。
- `ADODB.Stream`: 文字列のエンコーディング(UTF-8, Shift_JIS等)を正確にコントロールできる唯一無二のストリームコンポーネントです。
2. オブジェクトのライフサイクル管理(メモリリークを防ぐ)
VBScriptでは、ガベージコレクションが即時実行されないため、COMオブジェクトを大量に生成・破棄するループ処理ではメモリリーク(メモリ食い潰し)が起きやすいです。
上記の `Utf8EncodeChar` 関数内では、処理が終わるごとに `Set node = Nothing`、`Set dom = Nothing` と明示的に参照を切っています。これにより、長時間のバッチ処理でも安定して動作する頑健なコードになっています。
—
陥りやすい罠とエラー回避のポイント
現場でVBScriptを書く際、初心者が必ずハマる「落とし穴」がいくつかあります。プロの視点から事前に対策を共有しておきます。
罠1: ProgIDのバージョン違いによるエラー
よくネットで見かけるコードには `MSXML2.DOMDocument` や `Microsoft.XMLDOM` が使われていますが、古いWindows環境やセキュリティ設定によっては動作しないことがあります。
> 対策: 現代のWindows環境では、最もセキュアで高速な `MSXML2.DOMDocument.6.0` を明示的に指定するのがエンジニアの鉄則です。
罠2: 文字コードの不一致(文字化け)
Web APIの多くは `UTF-8` を要求しますが、VBScriptが動くWindowsのコンソール(Cscript / Wscript)や古いVBAの既定文字コードは `Shift-JIS` です。
> 対策: スクリプトファイル自体の文字コードを 「UTF-8 (BOM付き)」 もしくは 「ANSI(Shift-JIS)」 に統一し、上記コードのように `ADODB.Stream` で明示的に `Charset = “UTF-8″` を指定することで、文字化けを完全にかわすことができます。
—
おわりに:ここをクリアすればVBScriptは怖くない!
今回は、`MSXML2.DOMDocument` を利用した洗練されたURLエンコード・デコードの実装方法を解説しました。
一見すると難解なCOMコンポーネントの連携も、オブジェクトの役割(役割分担)を理解してしまえば、VBScriptの表現力は劇的に広がります。「マクロの記録」や「決まりきったサンプルのコピペ」から抜け出し、こうした標準ライブラリの本質を突いたコードが書けるようになると、業務自動化のエンジニアとして圧倒的な自信がつくはずです。
ここをクリアしたあなたなら、どんなレガシー環境の自動化でも華麗にこなせるはず。ぜひ、実際の業務ツールに組み込んでその実力を体感してみてくださいね!
