2025年8月25日月曜日

VBSでUTF-8で読み書きする

■ ADODB.StreamのUTF-8読み書き

VBS自体は使えなくなるかもしれないんですがVBAや他の言語でも使えるので一応備忘
基本的にテキストの読み書きはFileSystemObjectを使うのですがShift-JISしか使えません。

今回はWebページのヘッダーのメタタグの機械的な変換をしたいなぁと思った時にWebページは全部UTF-8に移行済みだったので、じゃあ「ADODB.Stream」という事ですね。

ADODB.Streamで出来る事は主に2つ、文字コード指定してのテキストの読み書きとバイナリデータの読み書きです。

■UTF-8を読み込む

まずは読み込みから
htmlpath="c:\makewebsite\test.html"

With CreateObject("ADODB.Stream"):.Type = 2:.Charset = "UTF-8":.Open:.LoadFromFile htmlpath:html = .ReadText:.Close:End With

  1. 通常通りCreateObjectでオブジェクトを作ります。
  2. Typeは1がバイナリモード、2がテキストモードです。
  3. Charsetは文字コード、今回はUTF-8のhtmlを読み込むので UTF-8です。
  4. Openでストリームを開きます
  5. LoadFromFile にファイルパスを指定
  6. ReadTextでhtmlの内容を全て取得
  7. Closeでストリームを閉じます

■UTF-8で書き込み①

次に書き込み
htmlpath="c:\makewebsite\test.html"
retext="書き込む文字"

With CreateObject("ADODB.Stream"):.Type = 2:.Charset = "UTF-8" :.Open:.WriteText retext:.SaveToFile htmlpath, 2:.Close:End With

これでOK!単純に先ほど逆順に処理します

  1. CreateObject(ストリームオブジェクト)
  2. Type(2:テキストモード)
  3. Charset(文字コード:UTF-8)
  4. Openでストリームを開きます
  5. WriteText でストリームに書き込む
  6. SaveToFile でストリームを全て出力、2は上書き
  7. Closeでストリームを閉じます

■Byte Order Mark/バイトオーダーマーク

ただし、1つだけ問題があります。
ADODB.Streamの仕様上書き込みにはBOM(ばいとおーだーまーく)が入ります
これが何かというとファイル先頭の3byteを使ってテキストの種類を書き込みます。

通常あっても基本問題ありませんが、現在の主流はテキストの内容を見て自動判断する方式です。windows10以降のデフォルト保存形式もUTF-8BOMなしです。

そしてwebで扱うHTMLもBOMは不要です。
普通のテキスト同じく基本的には問題ないものの、頭に3byteがクローラーなどの邪魔になる可能性がありBOMは消す必要があります。

■UTF-8で書き込み②(BOMなし)

With CreateObject("ADODB.Stream")
.Type = 2:.Charset = "UTF-8":.Open:.WriteText retext:.Position = 0:.Type = 1:.Position=3:tb=.Read:.Close
.Type = 1:.Open:.Write tb:.SaveToFile htmlpath, 2:.Close
End With

  1. CreateObject(ストリームオブジェクト)
  2. Type(2:テキストモード)
  3. Charset(文字コード:UTF-8)
  4. Openでストリームを開きます
  5. WriteText でストリームに書き込む
  6. テキストの状態でストリームの位置を0に
  7. Type(1:バイナリモードに変更)
  8. バイナリモードで開始位置を3byte移動
  9. Readで変数に4byte以降代入
  10. Closeでストリームをリセット
  11. Type(1:バイナリモード)
  12. Openでストリームを開きます
  13. Writeでストリームを書き込む
  14. SaveToFile でストリームを全て出力(2は上書き)
  15. Closeでストリームを閉じます

公式ドキュメントを見る限りCloseで閉じた後に再度Openで開いても問題なさそうなので1つのストリームでBOMを消しています。
処理が複雑そうになるならストリームは読み込みと書き込みで分けてください。

Closeメソッド
https://learn.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/close-method-ado

処理としては文字列情報をテキストストリームに変換
UTF-8でテキストストリームに書き込むとBOMが入る
テキストストリームの状態でポジションを0で先頭に戻す
バイナリモードにして先頭からBOM分の3byteをスキップさせ変数にbyteで代入
ストリームを切断後に開きなおし、ストリームにbyteを代入あとはSaveToFileで出力して終了。

■UTF-8で書き込み③(BOMなし)

With CreateObject("ADODB.Stream")
.type=2:.charset="UTF-8":.open:.writetext retext
.position=0:.type=1:.Position=3:tb=.Read
.position=0:.seteos:.write tb:.SaveToFile htmlpath, 2:.Close
End With

もう少し詰めるならこう。
BOM3byteを飛ばすところまでは同じ。
ストリームの位置を先頭に戻し、seteosでストリーム内容を完全消去します。
そこにストリームを書き込みなおして出力。

コードの評価をジェミニなどで通したときにBOMが必ずつくか分からないと言われて調べたけれど、BOMが付かない状況を探しても見つかりませんでした。

WriteText メソッド (ADO)
https://learn.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/writetext-method-ado

Charset プロパティ (ADO)
https://learn.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/charset-property-ado

そもそもBOMについての記載がなく、仕様説明ないまま使われてる技術怖い・・・。

0 件のコメント:

コメントを投稿