見出し画像

BOMなんとかしたい

本日の一曲。

「csv 文字化け」とかで検索すると色々と出てくるアレです。

下の動画、Tips的な展開を見せると思いきや、結局「間違って消したり上書きしちゃった時にはうちの製品使いなよ」的に強引に持っていく、ある意味潔い感じに話を組み立ててますね。ちゃんと「別の場所に保存ね」って言っているからまあevilではないかな。

CSV?

"The Comma Separated Value (CSV) File"のことです。","で区切られたテキスト列のファイルですね。

CSVファイルについての解説、RFC4180見ていくとStatusが "Informational" ってなってますね。これ、RFC8259で "Internet Standard" になっているJSONとは違って、「『標準規格』にまで至っていない」ということですね。ですので、ほかの人から『CSVファイルの規格通りに』とかそういう風な話が出た場合にはもう少し細かく聞いてみた方が良い場面もあります。

このCSVファイル文字化けするんですけどぉ〜?

さて、ExcelでCSVファイルを読み込んだ時に何故か漢字や仮名を使っている部分が文字化けする、というケースがあると思います。

  1. OSはWindows

  2. CSVファイルを直接ダブルクリックで開いている(関連づけられたExcelが起動する設定)

  3. 他から送られてきたCSVファイル(orプログラム等で自動的に生成されたもの)

  4. 仮名と漢字、全角文字部分が文字化けしているっぽい

  5. 試しに直接テキストエディタで開いてみたけど文字化けは起こさなかった

上記のようなパターンで、「あれれ、おかしーなー?」ってなった時に、上記の動画のような方法を試す感じになるんでしょうね、っていうのは想像できます。

テキストエディタだと正しく見えるけど?

それは「テキストエディタ側がよしなにやってくれるから」。

とりあえず16進ダンプでも出してみましょうか…以下では「あ」一文字をそれぞれ以下のファイル名で保存しているとして話を進めます。

  • sample.txt - UTF8

  • sample_bom.txt - UTF8(BOM付き)

  • sample_sjis.txt - Shift-JIS

では今回はPowershellのhexdumpコマンドを使った出力で中身を見てみましょう。

PS /private/tmp> Get-ChildItem *.txt | select name

Name
----
sample_bom.txt
sample_sjis.txt
sample.txt

PS /private/tmp> hexdump sample.txt     
0000000 e3 81 82                                       
0000003
PS /private/tmp> hexdump sample_bom.txt 
0000000 ef bb bf e3 81 82                              
0000006
PS /private/tmp> hexdump sample_sjis.txt
0000000 82 a0                                          
0000002
PS /private/tmp> 

Windows メモ帳で開いてみて「右下」を確認

最近のWindows メモ帳だと、開いたファイルの文字コードおよびBOM有り無しをステータスバーに表示してくれます。

実は「ファイル読み込み時にテキストのエンコーディングを自動的に判定する」ことをやっていることがあります。なので先ほど挙げた3種類とか気にする必要がこれまでなかった、ということかもしれません。

ひとまずほかのエディタでも、テキストのエンコーディングを判別して編集できるようにしていること、また多くはステータスバー等で使用エンコーディングやBOM有り無しの情報を表示してくれます。試してみたらいいさ。

ExcelでBOMなしUTF8のファイルを開いてみた

お約束的な流れではありますが、sample.txt(UTF-8,BOMなし)を sample.csvというファイル名に変更して、Excel で開いてみると…

UTF-8、BOMなしの「あ」.csv

わーいやったー、文字化けしてるー。

  • sample.csv- UTF8 ※文字化け発生

  • sample_bom.csv - UTF8(BOM付き)

  • sample_sjis.csv - Shift-JIS -

じゃあBOMつけてあげれば良いので、こうかな?

[byte[]]$b=@(0xef,0xbb,0xbf)
[byte[]]$c=[System.IO.File]::ReadAllBytes('./sample.txt')
$o=$b+$c
[System.IO.File]::WriteAllBytes('./sample_bom.csv',$o)

16進ダンプで確認。

PS /private/tmp> hexdump sample_bom.csv
0000000 ef bb bf e3 81 82
0000006
PS /private/tmp> cat sample_bom.csv
あ

これでExcelで開いても安心ですね(?)

お読みいただきありがとうございます。サポートいただいた分はおやつのグレードアップに使おうかと思います。スキ、SNSにシェアもよろしくお願いします!