BlueprintLab Deep Guide
CSVの区切り文字・引用符・改行完全ガイド――全部A列・列ずれを構造から直す
文字は読めるのに全部A列、ある行から急に列がずれる。そんなときは文字コードより、区切り・引用符・改行という「CSVの構造」を見ます。
CSVをExcelで開いた。
日本語は普通に読める。
なのに、全部A列に入っている。
あるいは最初の100行はきれいなのに、商品説明にカンマが入った行から急に列がずれる。
この場合、UTF-8やShift_JISを何度変えても直らないことがあります。
問題は文字ではなく、「どこまでを1つの値として読むか」だからです。
CSVは見た目が単純なぶん、区切り・引用符・改行の境界がかなり大事です。
「CSVなんだからカンマ区切りでしょ?」――基本はそう。でも実務では違うことがあります
CSVはComma-Separated Valuesなので、名前どおり基本はカンマ区切りです。
name,age,city
山田,35,東京
ところが実務では、タブ、セミコロン、パイプなどを区切りに使うデータもあります。
name[TAB]age[TAB]city
name;age;city
name|age|city
しかも、拡張子が .csv のままなのにセミコロン区切り、ということもあります。
なので「文字は読めるのに全部A列」なら、最初に見るのは文字コードではなくDelimiterです。
Excelなら、[データ]→[テキストまたはCSVから] のプレビューでカンマ、TAB、セミコロンなどを切り替えます。
列がパッと正しい位置へ分かれたら、その区切り文字が当たりです。
途中の行だけずれるなら、値の中のカンマを見ます
例えば商品名が、
Large, Red Mug
だったとします。
CSVへそのまま書くと、こうなります。
id,name,price
A001,Large, Red Mug,1980
人間には「商品名の中にカンマがある」と分かります。
でもCSVパーサーから見ると、カンマは列の境目に見えます。
そこで、1つの値全体をダブルクォートで囲います。
id,name,price
A001,"Large, Red Mug",1980
これで「このカンマは区切りではなく、値の中身です」と伝えられます。
CSVでダブルクォートは、飾りではなく“境界線を守るための印”なんです。
値の中に " を入れたいときは、さらに少し変わった書き方になります
例えば、備考欄にこう書きたいとします。
サイズは"Large"です
CSVでは通常、引用符の中の " を2つ重ねます。
id,note
A001,"サイズは""Large""です"
初めて見ると、かなり読みにくいですよね。
でもCSVパーサーには、
- 外側の
"はフィールドの囲み - 内側の
""は文字としてのダブルクォート
と伝わります。
手作業でCSV文字列を組み立てると、こういうエスケープでミスが出やすくなります。
アプリからCSVを書き出すなら、実績のあるCSVライブラリや正規のエクスポート機能を使う方が安全です。
セルの中に改行があっても、CSVとしては1行分のデータにできます
自由記述や住所には、セル内改行が入ることがあります。
例えば、
id,note,status
A001,"1行目
2行目",ok
テキストエディタで見ると、レコードが途中で2行に割れたように見えます。
でもダブルクォートの中にある改行なら、CSVパーサーは1つのフィールドとして扱えます。
ここで「ファイルの物理的な1行=CSVの1レコード」と単純に考えると、解析を間違えることがあります。
自由記述が入るCSVでは、行数を数えるだけでも少し注意が必要です。
空欄と「列そのものが足りない」は、似ているようで別です
例えば4列のうち3列目だけ空なら、こう書けます。
A001,山田,,東京
カンマが連続していて、その間に空のフィールドがあります。
これは「3列目という場所はある。でも値がない」という状態です。
一方で、行そのもののフィールド数が足りなければ、列構造が違います。
大量CSVで「ある行だけ列ずれ」する場合、ヘッダーの列数と各レコードの解析後フィールド数を比べるだけでも異常行をかなり絞れます。
ただし、テキスト上のカンマの数を単純に数えてはいけません。
引用符の中のカンマは列区切りではないからです。
RFC 4180を知っておくと、「普通のCSV」の基準ができます
CSVには、歴史的にかなり実装差があります。
RFC 4180は、その中で広く使われている形式を文書化したInformational RFCです。
例えば、
- レコードを行で区切る
- ヘッダー行は任意
- フィールドはカンマで区切る
- カンマ、改行、ダブルクォートを含むフィールドは引用する
- 引用フィールド内の
"は""として表す
といった形が文書化されています。
ただし、ここを「CSVの法律」だと思うと少し違います。
RFC 4180自身も、CSVにはさまざまな仕様・実装があることを前提にしています。
取込先が「セミコロン区切り」「CRLF必須」「ヘッダーなし」など独自ルールを決めているなら、その仕様が実務上の正解です。
RFC 4180は、相手の仕様がないときに共通の基準を持つためのものと考えると分かりやすいです。
「列ずれした10万行」を全部見る必要はありません
大量CSVで途中からずれると、ファイル全体を目視したくなります。
でも見るべきなのは、最初に構造が変わった場所です。
順番はこうです。
- ヘッダーのフィールド数を確認する。
- CSVパーサーで各レコードのフィールド数を見る。
- 最初に列数が変わるレコードを特定する。
- その前後で引用符、カンマ、改行を見る。
- 商品説明・住所・備考など、区切り文字を含みやすい列を重点的に見る。
ここまで絞れれば、10万行でも見る場所は数行で済むことがあります。
全部を読むのではなく、最初に境界が壊れたところを探す。
これが列ずれ調査のコツです。
壊れにくいCSVを作るなら、「全部自分でエスケープしない」がいちばん効きます
CSVは仕様が単純なので、つい文字列連結で作れそうに見えます。
value1 + "," + value2 + "," + value3
最初は動きます。
でも値にカンマ、改行、ダブルクォートが入った瞬間に分岐が増えます。
なのでアプリからCSVを出すなら、既存のCSVライブラリに引用処理を任せる方が安全です。
人がExcelなどで編集する場合も、最終的には、
- 想定した区切りで列が分かれる
- レコードごとのフィールド数が合う
- カンマ・改行・引用符を含む値が正しく引用される
- 文字コードが取込先仕様と一致する
- 少量で取込テストできる
ところまで見ます。
CSVは単純なんですが、単純だからこそ“境界”が壊れると全部ずれるんです。