エンタープライズ寄りなアプリケーションを作っていると、データベースの内容をCSVファイルとしてエクスポートしお客さんに編集してもらい、再度インポートするという処理を書く時がある。
この時、お客さんから我々のアプリケーションに送られてくるCSVファイルの文字コードは、以下の3パターンが考えられると思う。
- BOM付きUTF-8
- お客さんがCSVファイルをExcel上で編集し、そのまま上書き保存したもの。
- BOM無しUTF-8
- お客さんがCSVファイルを保存時にBOMを削除してくるソフトウェア1上で編集し、上書き保存したもの。
- Shift JIS
- お客さんがCSVファイルをExcelブック(xlsxファイル)として保存した後、CSVファイルとしてエクスポートしたもの。
これら3パターンをいい感じに扱うコードがこちらだ。
require 'nkf'
# 文字コード検証部分
headers_str = params["csv"]["tempfile"].readline # 1行目のヘッダ部分だけ取得
encoding = NKF.guess(headers_str) # NKFモジュールで文字コードの判定
encoding = "BOM|#{encoding}" if encoding == Encoding::UTF_8 # UTF-8なら、 BOM| をつける。
# CSVファイル読み込み部分
CSV.foreach(params["csv"]["tempfile"], encoding: encoding).each do |row|
# 何らかの処理
end
以下にポイントだけ書いておく。
-
NKF.guess
はEncoding
オブジェクトを返す。 - RubyのNKFモジュールはBOM付きUTF-8とBOM無しUTF-8を区別してくれないようなので、NKF.guessの返り値がUTF-8な時は一律で
BOM|
をつけている。- CSV.foreachのencodingオプションに 'BOM|UTF-8' を渡すとBOMがある場合は自動的に取り除いてくれるので、BOM無しUTF-8文字列を渡しても問題ない
-
BOM|Shift_JIS
のような文字列を渡してしまうと問題なので、if encoding.to_s == "UTF-8"
という条件を付けている。
「こんなCSVが送られてきたらダメでしょ!」など、なにかツッコミあったらやさしく教えてください。
-
そんなものあるのか?未検証。 ↩