メインコンテンツへ移動

CSV RFC 4180のルール

RFC 4180はCSVを正確に定義します。レコードはCRLFで区切られ、フィールドはカンマで区切られ、カンマ、引用符、改行のいずれかを含むフィールドは二重引用符で囲まれます。埋め込まれた引用符は""と2つ重ねます。ヘッダー行は任意、区切り文字はカンマ、MIMEタイプはtext/csvです。現実のファイルの大半は、この規格にざっくりとしか従っていません。

端末内で処理

CSV RFC 4180のルールとは

CSVはその仕様より古い存在です。カンマ区切りの値のファイルは何十年もやり取りされてきてから、RFC 4180が2005年10月に情報提供文書として公開されました。新しい設計ではなく、世界がすでに行っていたことを注意深く記述し、パーサ同士が合意できるように書き留めたものです。この出自が、文書の短さと、最もよく聞かれる批判の両方を説明します。規格は慣行を記述しており、慣行のほうが規格より先にあった、という批判です。

ルール自体は短いものです。ファイルはレコードの列であり、レコードはCRLFで区切られ、フィールドはカンマで区切られ、カンマ、二重引用符、改行のいずれかを含むフィールドは二重引用符で囲まなければならず、内部の引用符は2つ重ねて書きます。その他のすべて——エンコーディング、ヘッダー、行の長さの不一致——は、RFCが任意とするか実務に任せています。現実のファイルがずれていくのはこのためです。

このガイドでは、コピーできる実例とともに文法をルールごとになぞり、仕様が「may(〜してもよい)」と言っている箇所に印を付け、実際に出会う逸脱を一覧にします。バイトオーダーマーク、セミコロンの区切り文字、Unix系の行末。あちこちでリンクしているコンバーターは、完全な文法——引用符付きフィールドも埋め込まれた改行も含めて——を実装しており、すべてブラウザ内で動きます。

文法はパーサの出力から見るのが一番手っ取り早いものです。クォートの多いファイルをCSVからJSONへの変換ツールに貼り付ければ、上記のルールのひとつひとつが、組み立てられたJSONのフィールドとして現れます。ローカルでパースされ、アップロードは一切ありません。

作る側では、JSONからCSVへの変換ツールがRFC 4180が要求する箇所を正確にクォートします。データに含まれるカンマや改行も、表計算ソフトとの往復で無傷で済みます。

文法:レコード、フィールド、CRLF

RFC 4180の文法は1段落に収まります。ファイルはレコードから成り、各レコードはカンマで区切られたフィールドの列です。レコードはCRLF——Unixツールの裸のLFではなく、0x0D 0x0Aという2バイト——で区切られ、最後のレコードの末尾にCRLFが付くかどうかは任意です。フィールドはクォートされてもされなくても構いません。クォートは条件次第であり、スタイルではありません。ABNFの概要はfile = [header CRLF] record *(CRLF record); record = field *(comma field)で、括弧内のヘッダーが任意である点に注目してください。

最小限の準拠ファイル

id,name,score
1,Ada,99
2,Grace,98

レコードとして見た同じファイル

レコード1: id=1, name=Ada,   score=99
レコード2: id=2, name=Grace, score=98

(各レコードは2バイトのCRLFで終わる。
最後のレコードでは省略してもよい)

クォート:二重引用符だけで出来ているエスケープ機構

フィールドは必要なときに二重引用符で囲まれます。そして、クォートされたフィールドの中に二重引用符を入れる唯一の方法が、それを2つ重ねることです。クォート内の""は、1個のリテラルな引用符を意味します。これがエスケープ機構のすべてです。バックスラッシュも、名前付きエンティティも、2つ目の引用文字もありません。シングルクォートはただのデータですし、カンマの後に迷い込んだスペースは次のフィールドの一部です。スペースは保存され、切り詰めてはならないと、仕様は明言しています。

欲しい値RFC 4180でのフィールド理由
plainplainクォートは任意。裸の形が既定
with, comma"with, comma"カンマを含むフィールドはクォート必須
with " quote"with "" quote"埋め込まれた引用符はクォート内で2つ重ねる
with newline"with newline"クォートされたフィールドは改行を含めてよい
padded padded スペースはデータ。クォートは任意、切り詰めは禁止

1つのレコードに、クォートのルールが全部詰まった例

year,quote,note
1962,"she said ""look, no hands""","multi-word, no problem"

パース結果のフィールド

year   → 1962
quote  → she said "look, no hands"
note   → multi-word, no problem

フィールド内の改行とカンマ

クォートされたフィールドは改行を含めてよいため、CSVの1行は1レコードとは限りません。\nでの素朴な分割は、複数行のフィールドを含むファイルを必ず壊します。住所ブロック、備考カラム、CSVに埋め込まれたJSONペイロードが素朴なインポーターを壊すのはこのためです。準拠したパーサは小さな状態機械です。クォートの中ではカンマも改行もデータ、外では区切り文字。split()だけでは正しく書けません。

同じ状態機械が、二重引用符のエッジケースも片付けます。値の途中で開く引用符、ファイル末尾で閉じられていない引用符、フィールドの一番最後にある重ねられた引用符。これらはまさに、RFC 4180のわずかなルールが解決するために書かれたケースであり、まさに手書きのパーサ同士が食い違う場所です。「Excelでは開けるのにインポーターで壊れる」報告のほとんどの発生源です。

2レコード、3つの物理行

name,address
"Ada","12 St James Square,
London"
"Grace","1 Loop Rd"

準拠パーサが返すもの

レコード1: Ada | 12 St James Square,
London
レコード2: Grace | 1 Loop Rd

(住所内のカンマはデータの一部。
引用符内のCRLFも同様)

CRLF、任意のヘッダー、そしてtext/csv

仕様で確定しているのに、日常では逆に決め込まれている細部が3つあります。レコードはCRLFで終わる——ただし最終レコードは省略できて、毎日使うパーサはどれも裸のLFを受け付ける。最初のレコードは列名を含めてもよいが、文法上は任意です。ヘッダーはフォーマットがサポートする慣行であって要求する構造ではないため、1行目がデータかどうかをツールに教えるか、あるいはツールが推測するしかありません。そして登録済みのMIMEタイプはtext/csvです。RFC 4180自身が登録したもので、charsetパラメータは送信者に委ねられています。

RFCが固く引く線がもう1つあります。区切り文字はカンマだということです。セミコロン区切りのファイルは、表計算ソフトのロケール慣行——小数点にカンマを使う地域では標準的——であって、規格が認めるバリアントではありません。準拠した書き手は決して推測せず、準拠したパーサは区切り文字を推測するか教えてもらうかします。しかしファイル自体は、どの慣行に従っているかの印を一切持ちません。

現実のファイルが規格からずれる箇所

現実のCSVはRFCより先にあるため、逸脱は例外ではなく常態です。「このCSVがパースできない」事案のほぼすべては、次の5つのずれに帰着します:

良いツールは、黙って推測するのではなく、こうした逸脱を表面化させます。ファイルが重要である場合——請求書、金融データの取り込み、監督機関が読むかもしれないあらゆるもの——は、上の文法と照らし合わせ、下流のパーサ全部に同じ例外を教え込む代わりに、源流でずれを直してください。

ずれ典型的な発生源何が壊れるか
ヘッダーの前のUTF-8 BOM表計算ソフトの「CSV UTF-8」書き出し最初の列名に3つの不可視バイトが付く
LFのみ、または混在する行末Unix系ツール、手で編集されたファイル厳格なCRLF分割器がレコード境界を誤読する
セミコロンやタブの区切り文字英語圏以外の表計算ソフトのロケールカンマ専用のパーサが列を結合する
一貫しないクォート不完全な書き出し、手作業の編集クォートが均一だと決め込んだパーサが値を誤読する
歯抜けの行手作業の編集、いい加減な結合フィールド数の決め込み、下流での列ずれ

往復に耐えるCSVを書く

信頼できる書き手のチェックリストは、文法から直接導けます。クォートは均一に。全フィールドか、ルールが要求するフィールドだけか。どちらも準拠ですが、読み返すときの安全度は均一のほうが上です。CRLFを出力し、ヘッダー行を書き、UTF-8でエンコードする。表計算ソフトに認めてもらう代償としてBOMが付くことも、ある程度は受け入れる。そして重要なものは必ず往復テストします。書いたばかりのファイルをパースし、全フィールドが元データと一致することを確認してから出荷する。繰り返し起きる失敗モードはいつも同じです。書き手がクォートしなかった、区切り文字を含む値です。

よくある質問

ここでリンクしているコンバーターを使うと、CSVはアップロードされますか?

いいえ。このサイトのCSVからJSONへの変換ツールとJSONからCSVへの変換ツールは、パースも出力も完全にブラウザ内で行います。アップロードの手順はなく、サーバー側のコピーもなく、実行中はNetworkパネルが空のままです。サイトのContent-Security-Policyも外部への接続をブロックするため、表計算ソフトから貼り付けた顧客データがタブの外に出ることはありません。

CSVファイルでヘッダー行は必須ですか?

規格上は必須ではありません。RFC 4180の文法では、最初のレコードは他のレコードと同じく任意です。ヘッダーは規格が許す慣行であって、強制する構造ではありません。実際の受け手はまちまちです。データベースのインポーターは1行目がデータか名前かを宣言するよう求めることが多く、表計算ソフトは単純にヘッダーがあるものとして扱います。

CSVファイルにカンマではなくセミコロンが使われているのはなぜですか?

それは別の規格ではなく、表計算ソフトのロケール慣行です。小数点にカンマを使うロケールでは、3,14のような数値がフィールドの区切りと衝突しないよう、セミコロンを採用しました。RFC 4180は区切り文字をカンマと決めているため、ツールはファイルを推測するか、設定オプションを設けるか、あるいは誤パースするかになります。だからこそ、書き出しはローカルでは問題なく開くのに、下流で壊れることがあります。

CSVのフィールド内に引用符を入れるにはどうすればよいですか?

クォートされたフィールドの中で、引用符を2つ重ねます。値say "hi"は、ファイル内では"say ""hi"""になります。内側の引用符がペアに重なり、重なったペアが閉じ引用符と出会うところでは3つ連なります。この重ね方が、このフォーマットの唯一のエスケープ機構です。バックスラッシュもエンティティもありません。クォートしていないフィールドに引用符を入れることは規格上まったく認められず、これを許すかどうかはパーサによって割れるため、移植性のある形では常にフィールドをクォートし、内側の引用符を2つ重ねます。

1つのCSVレコードが複数行にまたがることがあるのはなぜですか?

クォートされたフィールドは改行を含めてよいため、レコードと物理行は別物です。1つのフィールドに3行の住所が入れば、1レコードが3行にまたがります。\nをレコード境界として扱う分割器は、そこから先のファイルを壊します。準拠したパーサは、自分がクォートの中にいるかどうかを追跡します。split()ではなく、小さな状態機械です。

CSVが実際に要求する行末は何ですか?

RFC 4180はレコード間のCRLF——0x0D 0x0Aの両バイト——を定めており、最終レコードでは省略が許されます。現実の世界はもっと緩いものです。Unix系ツールは裸のLFを出し、手で編集したファイルには混在した行末が現れ、パーサの多くは3種類すべてを受け付けます。表計算ソフトと相互運用しなければならない書き手はCRLFを出すべきで、読み手はそれ以外を許容すべきです。

ここで引用した規格はどこで読めますか?

  • RFC 4180 — CSV(カンマ区切り値)ファイルの共通形式とMIMEタイプ