vbscriptでNode.jsの標準出力を文字化けせずに受け取る

node.jsはjavascriptのプラットフォームであり簡単にネットワーク関連のプログラムを書く事ができます。そしてスクリプトを簡単に実行ファイルにできます。
ネット関連の部分をnode.jsで動かし結果をjson文字列にして標準出力に出す実行ファイルを作り、その標準出力をvbscriptで読み込もうとしました。
これって文字化けするんですね。

node.jsのスクリプトとその実行ファイルを単体でコマンドプロンプトで動かす分には文字化けも起こさず2バイト文字を表示します。
vbscriptでその実行ファイルをWScript.ShellのExecメソッドで動かしてやれば簡単に実行結果のjson文字列を標準出力から得られると思ったのですが、これだと文字化けします。

やはりWindowsでLinux系のプログラムを使おうとすると文字コード問題にぶち当たります。改めて基本的な文字コードを調べるとnode.jsはUTF-8で、Windowsはunicode(UTF-16)で動いています。

という事でnode.jsの出力をUTF-16にしてやります。文字コードが異なるので文字のまま扱うことができません。1バイト配列のバッファに変換します。
const iconvlite = require("iconv-lite");
var buf = iconvlite.encode("出力したい文字列", "UTF-16");
var json = {
            output: buf
}
console.log(JSON.stringify(json));
こんな感じでjson文字列を標準出力へ出します。

vbscriptではnode.jsのスクリプトをWScript.ShellのExecメソッドで動かして標準出力を受け取ります。
Set objWshShell = WScript.CreateObject("WScript.Shell")
ret = objWshShell.Exec("[node.jsのスクリプト]", 1, True).StdOut.ReadAll
これでnode.jsからのjsonデータを受け取りました。

json文字列はjscriptのeval関数でjsonオブジェクトへ変換します。
var json = eval('(' + str + ')');
strは先ほどの標準出力を受け取った文字列が入ります。文字列を括弧()でくくらないと評価されないそうです。セキュリティがうるさい昨今vbscriptから直接jscriptを作れないようです。jscriptだけ別ファイルにしてWSFの機能を利用しvbscriptとjscriptの関数を相互に利用します。

vbscriptではこの結果を例えば
byteString = json.output.data
とするとjson内のバイト配列を取得できます。

そしてこのバイト配列を文字列へ変換します。こんな関数を用意します。
'文字列エンコード
'data:バイト配列
Function stringEncode(data, chset) 
  dim objStm
  Set objStm = CreateObject("ADODB.Stream")
  with objStm
    .Open
    .Type = 1
    .Write ArrayToBArray(data)
    .Position = 0
    .Type = 2
    Select Case UCase(chset) 'BOM
      Case "UNICODE", "UTF-16"
        .Position = 2
      Case "UTF-8"
        .Position = 3
    End Select
  End With
  stringEncode = objStm.ReadText()
  objStm.Close
End Function

'数値配列をHEX表記文字列に
Function ArrayToBArray(data)
  dim h,b,a
  for each a in data
    b = Hex(a)
    if len(b) = 1 then b = "0" & b
    h = h & b
  next
  With CreateObject("Microsoft.XMLDOM").createElement("New") 
    .DataType = "bin.hex" 
    .Text = h
    ArrayToBArray= .NodeTypedValue 
  End With 
End Function
ADODB.Streamでバイト配列をストリームへ書き込み、文字コードを指定し文字としてストリームを読み出します。バイト配列をストリームへ書き込むためMicrosoft.XMLDOMを使います。
この関数を次のように呼び出します。
ret = stringEncode(json.output.data,"UNICODE")
これで目的の文字列が取得できました。

何をしているんだかいつも途中でわからなくなります。文字コードの変換はとても面倒です。

コメント

最近のコメント

Threaded Recent Comments will be here.