先日ちょっとした"やっつけ仕事"を頼まれました。Excelで作られたテーブル、例えば:
こんなのを読み込んで適当な処理を施して欲しい、と。Excelのシートから各セルの値を拾い出すのはさほどに難しくはないのですが、いかんせん時間がなかったのでいったんはお断りしたところ、「Excelシートを直接読むのが面倒ならCSVからでもかまわん」とのこと。CSVならフツーにテキストファイルを読めばいいから小一時間で作れそう、昼メシ奢ってもらうのを報酬に引き受けることにしました。
CSVのフォーマット
CSV(Comma Separated Values)はMS-DOSあるいはその以前からスプレッドシートのデータ・フォーマットとして使われています。CSVの規格/標準としてはRFC4180がありますが、こいつは2005年に作られたものでそれ以前のアプリケーションがRFC4180に準拠していることは期待できるはずもありません。とはいえ、まずはRFC4180に従って作られたCSVなら正しく読めることを目標とします。
RFC4180によりますと:
- データの単位をfield、fieldの列をrecordと呼ぶ。
- fieldの区切りはカンマ(,)、recordの区切りは復帰(CR)改行(LF)である。
- fieldはその全体を二重引用符(")で囲んでもよい。二重引用符で囲むことを"escapeする"という。
- fieldがカンマ/二重引用符/復帰/改行を含むとき、そのfieldはescapeしなければならない。
- escapeされたfield中の二重引用符は2つ並べよ(つまりfield内の"は""とし、さらに全体を"で囲め)。
とまぁ、ざっくりこの程度のルールが定められています。さきほどのExcelシートをCSVで保存したところ:
こんなCSVが得られました。RFC4180に従ったフォーマットになっているようです。
で、昼メシの賭かったアプリケーションではこのCSV形式のテキストファイルを読み込んで文字列の二次元配列、例えば string[][] や vector<vector<string>> を生成するのが最初の処理となります。
前述のとおり、RFC4180は言わば"後付け"の規格です。アプリケーションが吐いたCSVがRFC4180に従っていないこともあり得ます。なので少しばかりユルく読み取ることにします。すなわち上記ルールを緩和し、「カンマ/二重引用符/復帰/改行を含むとき、(field全体ではなく)その部分を含む一部をescapeしてもよい」とします。例えばfieldの値が apple,orange であるとき apple","orange としてもいい、と。