csv.txtってcsv？csvファイルの仕様について

こんにちは。じゅに[（@Jyu210_engineer）](https://x.com/Jyu210_engineer)です。

今回は前回までとうって変わって、csvファイルの仕様について書きたいと思います。

先日、古いシステムの解析を仕様書ベースで行っていた時に「おや？」というファイルに出会いました。

そのファイルこそタイトルにもある「**csv.txt**」です。

出会った瞬間は「**いやいやcsvじゃないやんw**」ってなりましたが、冷静に考えてみると自分が思っているcsvの仕様が正しいのか？という疑問がわいてきました。

「**自分が知らないcsvの世界があるのかも**」と思いましたね。

それらを解決するために自分なりにcsvの仕様をまとめてみようと思ったのがきっかけです。

csvファイルの仕様こそ、そこらへんにいっぱい転がってますし、国際規格もあるので今更感しかありませんが、お付き合いください。

## 前談
csvファイルは「**カンマで区切られたテキストファイル**」ということが良く出てきます。

まずこれが「**csv.txt**」というファイルが生まれた要因ですね。

上記の説明だけ見ると「**テキストファイル（.txt）の内容をカンマで区切れば良いのね**」っと思っても仕方ないのかなと。

csvファイルの仕様としては「**.csv**」という拡張子であることとなっていますが、ファイル連携で使用するだけであれば「**csv.txt**」であっても、該当ファイルを取り込んで、カンマ区切りで値を取得するだけにます。

プログラム的には取り込むファイルを探す時に拡張子が「.csv」であろうが「.txt」であろうが、取り込みたい拡張子を指定して取り込めば、カンマ区切りで処理するという内容は変わらないです。

後から詳細は記載しますが、csvファイルにはExcelで開けるといったような特徴、利点もあります。

しかし、プログラム内で使用するだけであれば拡張はなんだって良く、ファイルの内容も仕様を決めればなんでも良いんですよね。

## csvファイルの仕様
前談を長々と書いてしまいましたが、ここではcsvファイルの仕様を記載します。

csvとはComma Separated Valuesの略となっており、ファイルサイズが軽い、編集がしやすい、様々なアプリで互換性があるなどの理由からファイル連携やインポート/エクスポート昨日などで多くのアプリやシステムで使用されているのが現状です。

前述したとおりRFC 4180という国際規格で仕様が定義されています。
国際規格で定義されているとはいえ、微妙に使用用途や状況によって、完全にRFC 4180の仕様にそわない場合もありますが、とりあえずRFC 4180の記載内容をもとにまとめました。

参考にした記事は以下になります。
https://tex2e.github.io/rfc-translater/html/rfc4180.html

### 拡張子
前述した通り```.csv```になります。

これはもう説明不要かなと。

### MINEタイプ
```text/csv```です。

MINE（Multipurpose Internet Mail Extensions）タイプはもともとメールの添付ファイルを正しく扱うために作られた規格になります。

しかし、現在ではWeb（HTTP通信）やAPIなどに幅広く使用されるようになっています。

要は拡張子とは別にhttpリクエストヘッダーなどで、ファイルの種類を指定するものです。

では、今回この記事を書くきっかけとなったカンマ区切りで構成されたファイル「csv.txt」をMINEタイプで```text/csv```を指定するとどうなるのか？

基本的には拡張子よりもMINEタイプを優先してファイル内容を判断するというのが基本ですが、ブラウザやAPIの仕様によるというのが実情なので、あるブラウザやAPIでは問題ないけど、違うものだと問題が発生する可能性があります。

### 行の構成
1行目はヘッダー行として、カンマで区切られた項目の名称を記載することとなっています。
RFC 4180としては「**ヘッダー行は含まれる場合がある**」という記載になっているので、ヘッダー行は必須ではありません。

「**ヘッダー行の有無はMINEタイプで指定して**」とは記載されていますが、どのようにMINEタイプを指定するかまでは定義されていないという中途半端な感じになっています。

なのでヘッダー行の有無はAPI仕様書などでヘッダー行の有無を明記するしかないというのが現実ですね。

2行目以降はデータ行になるので、ヘッダー行に記載された内容に則したデータを記載していきます。

ヘッダー行、データ行ともに1データ以上が必要になり、ヘッダー行とデータ行の項目数（カンマの数）は同じにする必要があります。

また、行の改行は```CRLF```です。
ちなみに改行コードは```CR```と```LF```、それらを組み合わせた```CRLF```があります。
- ```CR```：Carriage Return。先頭行にカーソルが移動する。（行は変わらない）
- ```LF```：Line Feed。いわるゆる改行。
- ```CRLF```：```CR```と```LF```の組み合わせ。改行されて先頭行にカーソルが移動する。

ちょっと脱線した感はありますが、以下のようなファイル内容のイメージになります。

まずはOKであるデータの例から。
``` ok.csv
ヘッダー項目1,ヘッダー項目2,ヘッダー項目3 CRLF
1行目データ1,1行目データ2,1行目データ3 CRLF
2行目データ1,2行目データ2,2行目データ3 CRLF
3行目データ1,3行目データ2,3行目データ3 CRLF
```

次はNGパターンの1つ目。
改行コードの```CRLF``` が抜けている行があるパターンです。
``` ng1.csv
ヘッダー項目1,ヘッダー項目2,ヘッダー項目3
1行目データ1,1行目データ2,1行目データ3 CRLF
2行目データ1,2行目データ2,2行目データ3 CRLF
3行目データ1,3行目データ2,3行目データ3
```

上記だと最終行が終了していないと判断される場合があり、途中の行の```CRLF```が抜けていると、次の行と合わせて1行として扱われます。

NGパターンの2つ目。
ヘッダー行とデータ行の項目数が違う。
``` ng2.csv
ヘッダー項目1,ヘッダー項目2,ヘッダー項目3
1行目データ1,1行目データ2,1行目データ3 CRLF
2行目データ1,2行目データ3 CRLF
3行目データ1,3行目データ2,3行目データ3 CRLF
```

NGパターン3つ目。
ヘッダー行またはデータ行に項目が1つもない。
``` ng2.csv
ヘッダー項目1,ヘッダー項目2,ヘッダー項目3
1行目データ1,1行目データ2,1行目データ3 CRLF
CRLF
3行目データ1,3行目データ2,3行目データ3 CRLF
```

NGパターン4つ目。
行がカンマで終了している。
``` ng4.csv
ヘッダー項目1,ヘッダー項目2,ヘッダー項目3 CRLF
1行目データ1,1行目データ2,1行目データ3, CRLF
2行目データ1,2行目データ2,2行目データ3 CRLF
3行目データ1,3行目データ2,3行目データ3 CRLF
```
ちなみにカンマで終了した場合、もう一つデータがあるという扱いになります。

### 二重引用符（ダブルクォーテーション）
二重引用符（ダブルクォーテーション）でデータを囲むことで、本来は区切り文字であるカンマ（,）をデータとして扱うことができます。

以下のようなイメージです。
``` double_quotation_mark.csv
ヘッダー項目1,ヘッダー項目2,ヘッダー項目3 CRLF
1行目データ1,"1行目データ2,カンマ入り",1行目データ3 CRLF
2行目データ1,2行目データ2,2行目データ3 CRLF
3行目データ1,3行目データ2,3行目データ3 CRLF
```

データ行1行目（ファイルとしては2行目）の```"1行目データ2,カンマ入り"```は途中にカンマ（,）が含まれていますが、このカンマ（,）は区切り文字とは判断されません。

Excelで開くと1セルに収まるというイメージですね。

しかし、APIなどでのやり取りになると二重引用符（ダブルクォーテーション）で囲まれた内容は1データとすることが基本だとは思いますが、API仕様書などに明記しておくほうが無難だと思います。

また、二重引用符（ダブルクォーテーション）で囲んだデータの中に二重引用符（ダブルクォーテーション）を入れたい場合は二重引用符（ダブルクォーテーション）を続けて記述することでエスケープ可能です。

```"1行目データ2""カンマ入り"```といった感じですね。

これは```1行目データ2"カンマ入り```と扱われます。

### 文字コード
これはRFC 4180では文字コードには特に触れられていません。

そのためか使用される環境やツールによってバラバラであるというのが現状です。

よくある例としては以下の通りです。

| 環境 | よく使用される文字コード |
|---|---|
|日本のWindows|Shift_JIS|
|Excel（日本語）|Shift_JISまたはBOM付きUTF-8）|
|Linux|BOMなしUTF-8|
|Mac|BOMなしUTF-8|

これらはあくまでも例なので、日本のWindowsであっても使用するツールによってはUTF-8が使われたりします。

ですので、ツールやAPIで使用する場合は文字コードについてもきちんと仕様書に記載することが大切です。

### 区切り文字
最後に区切り文字です。

これはcsvの名前の通り、カンマ（,）になります。

しかし、派生としてタブやパイプ（|）、スペースが区切り文字として使用される場合もあります。

RFC 4180ではカンマ（,）と定義されているので、正式にはカンマ（,）区切りのみがcsvにはなるのですが、タブやパイプ（|）、スペース区切りのファイルもcsvと呼ばれることがあるので注意が必要です。
（Excelでタブやパイプ（|）、スペース区切りのファイルを開いても、区切り文字の設定によってはきちんとデータがセルに分割されます）

一応、タブやパイプ（|）、スペース区切りのファイルは以下とも呼ばれたり、その呼称が拡張子として使用される場合があります。
| 区切り文字 | 呼称/拡張子 | 英語での呼称 |
|---|---|---|
|タブ|tsv/.tsv|Tab-Separated Values|
|パイプ|psv/.psv|Pipe-Separated Values|
|スペース|ssv/.ssv|Space-Separated Values|

以前自分はファイルではありますが、区切り文字にキャレット（^)を使用した経験もありました。
（なんか超昔からのこだわりっぽかったです）

## まとめ
結果的に目新しい情報を得ることはできませんでしたが、RFC 4180のことを知れたし、些細な事でもきんと深掘りする、理解するという大切さはあるのかなと思いました。

とはいえ、csvに対してここまで時間を使うのは・・・という点もあるので、「**csv？カンマ（,）区切りのファイルでしょ**」ぐらいの感覚で良いのかなと。
（その感覚で今まで困ったことはありません）

気をつける点としては、csvと言っても区切り文字がカンマ（,）でない場合もあるので、仕様書に区切り文字や文字コードなどにきちんと明記しようねと言ったところでしょうか。

おそらくcsvはまだまだ使用されるファイル形式ではあると思うので、どなたかの参考になれば幸いです。