Fusic Tech Blog

Fusion of Society, IT and Culture

[Rails]CSVダウンロード機能を細部まで理解して実装する(2)Windows対応BOM付きUTF-8
2021/10/15

[Rails]CSVダウンロード機能を細部まで理解して実装する(2)Windows対応BOM付きUTF-8

この記事は、こちらのQiita記事 [Rails]CSVダウンロード機能を細部まで理解して実装する(1) の続きです。

「よっしゃー、実装終わったー!」と思って満を持してプルリク出したら、先輩から

「Windowsだと文字化けするよー。BOM付きUTF-8対応よろしくー。」

と言われました。

BOM... ??
:bomb: ??

そもそも

BOMとは?

BOMとは、Byte Order Markの略。
バイトの順番のマーク?
要は、データが何の文字コードであるかを伝達するために先頭に付けるおまじないらしい。 IT用語辞典 e-wordsがいつも通りわかりやすい!

e-wordsさんを読むと、

  • 元々はUTF-16用のもの
  • UTF-16は2バイト(もしくは4バイト)の固定長で文字を表現する(=>要は複数バイトになる)
  • 複数バイトだとどっちが先でどっちが後のものかわからなくなるので、こっちが先だよ!と示す必要があり、いくつか方式がある
  • 上位バイトが先頭:UTF-16BE、下位バイトが先頭:UTF-16LE。こんな風に考えると覚えやすい?↓
  • BE:Big endian。ビッグ=大きい方、つまり上位バイトを、エンド=終わり、つまり下位とする。
  • LE:Little endian。上の逆。
  • ちなみに、このBEとかLEは文字コードだけでなく、コンピューティング全般で使う用語。Wikipedia
  • その方式を伝達できない場合、文書の先頭にマークするらしく、それがBOM(Byte Order Mark)ということらしい!
  • じゃ、なんでそれをUTF-8に使うの?というと、この文書がUTF-8ですよ!ということを示すため。
  • UTF-16みたいにバイトの順番を示すものではないけど便宜的にこれもBOMと呼ぶと。

なるほど!

文字コード BOM
UTF-16BE FE FF
UTF-16LE FF FE
UTF-8 EF BB BF

もっと似通った感じにして欲しかったなぁ。UTF-16BEならFF BEとかw
さて、なんとなくBOMがわかってきたところで実装開始。

で、なんで文字化けすると?

Windowsでは文字コードとしてよくShift_JISが使われるらしく、ExcelがCSVファイルを開くとデフォルトでShift_JISで読み込むんだとか。UTF-8で書かれた文書を無理やりShift_JISで解釈しようとするから文字化けするのですね。ですがUTF-8で出力する際にこのBOMを付けることでExcelにUTF-8で書かれていると認識させることができます。

実装!

BOMとは何かは初心者にはちょっと身構えてしまう内容かもしれませんが、実装自体は少しのプログラムで解決します。

require 'csv'

bom = %w[EF BB BF].map { |e| e.hex.chr }.join

CSV.generate(bom) do |csv|
 csv << ['日付', '名前', 'ニックネーム']
 csv << ['0424', '山田', '山ちゃん']
 csv << ['0425', '田中', 'サトシ']
 csv << ['0425', '内田', 'うっちー']
end

でも、なんか見慣れないメソッドが...

  • String#hex:レシーバーが16進数の数字が文字列であると解釈して整数に変換するメソッド。
  • Integer#chr:レシーバーを文字コードとして見て、エンコーディングに対応する文字を返す。引数なしの場合は、US-ASCII、ASCII-8BIT、デフォルト内部エンコーディングの順で優先的に解釈するそう。
  • CSV.generateの引数に渡す

本当BOMが付いているのか確認してみる

od -tx1 -Ax XXXXXXXX.csv
  • odコマンド:ファイルを指定されたフォーマットで表示する
  • -txオプション:tはTypeStringで、出力タイプの指定。xはバイトを16進数として表示する
  • -Axオプション:AはAdressBaseで、入力オフセット・ベースの指定。xはオフセットベースを16進数で書く。

なんかIBMのドキュメント→https://www.ibm.com/docs/ja/aix/7.1?topic=o-od-command

蛇足ですが、他にもodコマンドと調べてみると、「odは、ファイルを8進数や16進数などでダンプする」という記述がたくさん出てきます。ダンプって?ダンプカー?
どちらも同じdumpで、まさにダンプカーのように「どさっと落とす」という意味らしいです。 (ちなみに英語では、dump carではなくdump truckだとか)

ソフトウェアの分野では、コンピュータの記憶装置(メモリやストレージなど)に記録された内容をまとめて表示、印刷、記録などすることや、そのようにして写し取られた内容のことをダンプという。
e-wordsより

本題に戻って、このodコマンドでダウンロードしたCSVファイルを見て、、いやダンプしてみると、確かに先頭にef bb bfの文字が入っている!!

これでWindowsで開いても文字化けしなくなりました!
おもしろいですなぁ。

kakudaisuke

kakudaisuke

IoT