lycheejam's tech log

チラ裏のメモ帳 | プログラミングは苦手、インフラが得意なつもり。

VBAでUTF-8 BOM無しファイル出力

VBA文字コードを指定してファイル出力

いつも業務で作成するVBAツールはデータ全件突合など
データを加工して新規ブックに理解しやすい形式にして出力するものでした。

今回文字コードを指定してBOM無しファイルで出力する必要があったためその備忘録です。

概要

要件はこんな感じです。出力ファイルは特段CSVでなくてもいいです。
大事なのは
文字コードUTF-8でBOM無しで出力すること

ソース


gist757c053219e64645846b916b0d1426e5

※ADODBを使用するときは参照設定で参照してください。

今回のソースでは簡略化するために文字列を渡して
その文字列を単純に書き込んでいますが、
ループで回してやれば1行ずつ書き込む形式になります。

出力形式はほかの言語でも似たようなものなので特段ありません。

BOMとは何ぞや

プログラムがテキストデータを読み込む時、その先頭の数バイトからそのデータがUnicodeで表現されていること、また符号化形式(エンコーディング)としてどれを使用しているかを判別できるようにしたものである。*1

Unicodeかどうか判断するためのものらしい、UTF-16の場合はBEかLEの判定
なんでソース中で3バイト読み飛ばしてるのかって言うと
先頭に「0xEF 0xBB 0xBF」の3バイトが付くらしい

キャレット位置は0からスタートなので0, 1, 2とカウントして3バイト目から読み込む
そうするとBOMである3バイトの「0xEF 0xBB 0xBF」を読み飛ばすことができる

EOSとは何ぞや

ファイル読み込み時にも使用していたEOS
EOFの親戚かな?くらいにいつも思っていた。

BOMを潰した分、後ろにゴミが残るので、SetEOSで取り除く*2

後ろにゴミが残るってどう言うことっすか...

EOSプロパティ
現在の位置がストリームの最後にあるかどうかを示すブール値を返します。EOSは、ストリームにバイトがなくなるとTrueを返します。現在の位置の後にさらにバイトがある場合はFalseを返します。*3

調べてみるとEnd Of Streamの略らしい

キャレット位置が0バイト地点から書き込みを行った場合
挿入モードで書き込みが行われ先頭3バイトのBOMがそのまま行末に行くという認識でよろしい?
なので書き込み時点でのキャレット位置を行末とするためにSetEOSを使って
行末についているゴミを削除?

試してみたらビンゴでした。
f:id:HM_Atlas:20171124215223p:plain

うん、スッキリ

雑感

業務でシステム更新なんかの大仕事やってるとシステムが違えば
扱ってる文字コードも全然ちがったり
DBに合わせて文字コード変換したりと
いろんなところに気を配らないと行けなくて大変ですね。