VBScriptの深淵:BOM判定による文字コードの完全掌握
業務自動化の現場において、未だにレガシーなCSVやログファイルの解析は避けて通れない。特に「Shift-JISかUTF-8か」という、20年以上続くこの泥沼の戦いにおいて、`ADODB.Stream`に頼り切った安易な実装は、文字化けやランタイムエラーの温床となる。
真のエンジニアであれば、OSのライブラリに任せる前に、ファイルそのものの「出自」をバイナリレベルで特定すべきだ。今回は、VBScriptにおける文字コード自動判別の極限ロジックを伝授する。
—
1. なぜ「ADODB.Stream」の前に判定が必要なのか
多くの技術者は、`ADODB.Stream`の`Charset`プロパティを「utf-8」に決め打ちし、読み込みエラーに直面すると「ファイルが壊れている」と判断する。しかし、現実のシステム連携において送られてくるファイルは、BOMの有無すら統一されていないのが常だ。
誤った文字コードで読み込むと、メモリ上に展開された文字列は破壊される。後続の処理でデータベースへ書き込む際、不正な文字コードによってSQL ServerやOracleが悲鳴を上げ、トランザクションがロールバックされる事態を招く。これを防ぐための「門番」こそが、今回のBOM判定アルゴリズムである。
—
2. BOM判定のバイナリシグネチャ
ファイル先頭の数バイト(マジックナンバー)を読み取ることで、エンコーディングは確定できる。
| エンコーディング | BOM (16進数) |
| :— | :— |
| UTF-8 | `EF BB BF` |
| UTF-16 (BE) | `FE FF` |
| UTF-16 (LE) | `FF FE` |
| Shift-JIS / その他 | (BOMなし) |
※Shift-JISやEUC-JPには、標準的なBOMは存在しない。これらは統計的な推測や、特定のバイト列パターンによるヒューリスティックな判定に頼ることになるが、まずは「BOMの有無」という確実な事実を掴むことが先決だ。
—
3. 実装:メモリ効率を最大化した判定ロジック
以下に、無駄なオブジェクト生成を排除し、最小限のメモリ消費で動作する判定関数を示す。
‘ 文字コード判定関数
‘ 戻り値: “UTF-8”, “UTF-16”, “Shift-JIS” 等
Function GetCharset(ByVal filePath)
Dim adoStream, binData, bom
Set adoStream = CreateObject(“ADODB.Stream”)
‘ バイナリモードでオープン
adoStream.Type = 1
adoStream.Open
adoStream.LoadFromFile filePath
‘ 先頭3バイトを読み取り
binData = adoStream.Read(3)
adoStream.Close
Set adoStream = Nothing ‘ 即座にメモリ解放
‘ バイナリ比較用BOM抽出
‘ ADODB.Read は Variant 配列を返すため、AscBで評価する
If IsNull(binData) Then
GetCharset = “Shift-JIS” ‘ 空ファイル
Exit Function
End If
‘ バイト値を評価
Dim b1, b2, b3
b1 = AscB(MidB(binData, 1, 1))
b2 = AscB(MidB(binData, 2, 1))
b3 = AscB(MidB(binData, 3, 1))
‘ 判定ロジック
If b1 = &HEF And b2 = &HBB And b3 = &HBF Then
GetCharset = “UTF-8”
ElseIf b1 = &HFE And b2 = &HFF Then
GetCharset = “UTF-16BE”
ElseIf b1 = &HFF And b2 = &HFE Then
GetCharset = “UTF-16LE”
Else
‘ BOMがない場合はデフォルトのShift-JISとみなす(必要に応じて拡張)
GetCharset = “Shift-JIS”
End If
End Function
—
4. チーフアーキテクトからの助言:プロのこだわり
オブジェクトのライフサイクル管理
VBScriptはガベージコレクションの挙動が予測しづらい。`Set obj = Nothing` を省略するエンジニアが多いが、数万件のログを処理するバッチプログラムにおいて、これは致命的なメモリリークを招く。`ADODB.Stream`のような巨大なリソースを抱えるオブジェクトは、使用直後に必ず解放せよ。
Shift-JISの先にある「罠」
上記のコードはBOMの有無を判定するが、BOMのない「UTF-8」を判定するには、バイト列を走査してUTF-8の有効なシーケンスであるかを確認する「統計的解析」が必要となる。しかし、業務システムにおいては「BOMなしUTF-8を許容しない」という運用ルールを定める方が、コードの複雑性を抑え、保守性を高めるという判断を下すこともエンジニアの重要な責務だ。
拡張性の担保
もし判定対象に「UTF-8(BOMなし)」を含めたい場合は、`ADODB.Stream`で読み込んだテキストが空文字にならないか、あるいは正規表現で特定のバイトパターンを検索する処理を追加する。だが、それはあくまで「例外」であるべきだ。
—
結びに代えて
VBScriptは古い言語かもしれないが、OSの深層部を叩けるその能力は、現代のコンテナ化された環境においても「最後の砦」として機能する。コードを書くこと以上に、「システムが何を読み込もうとしているのか」というファイルの正体を暴くことこそが、トラブルを未然に防ぐ唯一の道である。
このロジックを君のライブラリに組み込み、二度と文字化けで泣かない環境を構築してほしい。健闘を祈る。
