CSV を壊さずに扱う
CSV はコンピューティングで最も単純な形式に見えます。値とカンマと改行だけですから。ところが実際には、最も多くのデータを静かに壊す形式です。単一の仕様がなく、書き出す側それぞれが少しずつ違う選択をするからです。ほとんどの CSV の問題はいくつかの曖昧さのどれかから生じており、それらに名前をつけられれば対処は自明になります。
値の中のカンマと引用符の規則
値が区切り文字を含んだ瞬間、形式にはエスケープが必要になり、慣例としてそのフィールドを二重引用符で囲みます。囲まれたフィールド内の引用符は二重に書きます。名前欄に入った Smith, John が "Smith, John" として現れる理由であり、引用符を含む値でそれが重なって見える理由です — 打ち間違いではなく、エスケープ規則です。
したがって CSV の一行をカンマで分割する方法は、どれほど魅力的でも機能しません。正しいパーサーは今引用符の内側にいるかを追跡し、囲まれたフィールドにはカンマも引用符も、さらには改行までも正当に入りえます。ファイルの途中から急に列が増えるなら、値の中のエスケープされていない区切り文字がほぼ常に原因です。
区切り文字は常にカンマとは限らない
カンマを小数点に使う地域では、表計算ソフトが CSV をセミコロンで書き出すことがよくあります。そのため、ある機械で完璧に開くファイルが別の機械では一列にまとまって落ちてきます。タブも広く使われており、値の中にタブが現れることがまれだという理由でより安全です。
区切り文字はファイルのどこにも宣言されないため、ツールは推測するしかなく、たいていは候補を試して列数が一貫する方を選びます。取り込みがうまくいかないとき、最も早く切り分けられるのが区切り文字であり、書き出す側を自分で握っているならタブ区切りがこの種の問題をまとめて回避してくれます。
文字コードと、BOM を欲しがる表計算ソフト
é のあるべき場所に é のように見えるテキストは、UTF-8 のファイルを旧来の1バイト文字コードとして読んだ結果です。CSV には文字コードの宣言がないため読む側は指示されるか推測するしかなく、推測を誤ると構造は無傷のまま非 ASCII 文字だけがすべて壊れます — だからこの損傷はデータベースまでそのまま生き延びがちです。
犯人はたいてい Excel です。多くの環境では、ファイルが UTF-8 のバイトオーダーマークで始まらない限り旧来のコードページを仮定します。BOM を書けばアクセント付き文字は正しく開きますが、代わりに先頭に見えない数バイトが付き、厳格なパーサーの一部はそれを最初の列名の一部として返してきます。事前に知っていれば、混乱の30分を節約できます。
表計算ソフトが黙って書き換える値
CSV に型はありません — すべて文字列です — なので意味を決めるのは読む側であり、表計算ソフトはそこで積極的です。郵便番号や商品コードを数値として読むと先頭のゼロが消えます。長い識別子は指数表記に変わります。日付らしく見える文字列は機械のロケールに合わせて書式が付け直され、同じファイルが二つのオフィスで違う結果を生む原因になります。
安全な手は、後から直すのではなく取り込みの時点でそうした列を文字列に指定することです。変換が起きた後では元の数字はもう失われています。文字そのものが重要なもの — 識別子、電話番号、各種コード — については、自動型判定を後で直す対象ではなく最初から切るべき機能として扱ってください。
CSV を別の形へ移す
JSON に変換すれば実際の型と入れ子が手に入り、検証がはるかに容易になります — ただし上記の曖昧さを明示的に解決することを強いるので、遅くよりも早く済ませる価値があります。逆方向、CSV から SQL の挿入文を作る場合は、同じエスケープの問題がより危険な形で戻ってきます。値の中の引用符は CSV ではなく SQL の規則でエスケープしなければなりません。
CSV を信用する前の短い確認:
- 解析の前に区切り文字を確認する — カンマ、セミコロン、タブのどれか。
- 文字コードを確認し、Excel 向けなら BOM を付ける。
- 区切り文字で素朴に分割せず、引用符で囲まれたフィールドを尊重する。
- 識別子的な列は文字列として取り込み、先頭のゼロを守る。
- 変換後は最初の数行だけでなく、行数と列数を確認する。