MCMDが処理する表構造データはFigure 2.5に例示されるようなCSV(Comma Separated Values)フォーマットである。 CSVは表構造データのフォーマットのデファクトスタンダードであり、アプリケーションプログラム間でのデータ交換用フォーマットとして 広く利用されている。
商品コード,商品名,分類,価格 0899781,パン,食品,128 8879674,オレンジジュース,飲料,98 3244565,チーズ,食品,350 6711298,茶碗,食器,168
しかしながら、CSVは標準化協会や企業主導で作成された標準フォーマットではなく、 それ故にベンダー毎にCSV の扱い方法が異なっているのが現状である。 その中で2005年10月にインターネット標準であるRFC4180としてCSVフォーマットが 提案されたのは注目すべき動きである。 Figure 2.6、RFC4180の中でABNF表現によるCSVの定義を示す。
(A) file = [header CRLF] record *(CRLF record) [CRLF] (B) header = name *(COMMA name) (C) record = field *(COMMA field) (D) name = field (E) field = (escaped / non-escaped) (F) escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE (G) non-escaped = *TEXTDATA (H) COMMA = %x2C (I) CR = %x0D ;as per section 6.1 of RFC 2234 [2] (J) DQUOTE = %x22 ;as per section 6.1 of RFC 2234 [2] (K) LF = %x0A ;as per section 6.1 of RFC 2234 [2] (L) CRLF = CR LF ;as per section 6.1 of RFC 2234 [2] (M) TEXTDATA = %x20-21 / %x23-2B / %x2D-7E 日本語翻訳:
Figure 2.6中の各行の意味は以下のとおりである。
(A) ファイル(file)は,ヘッダ(header)と1行以上のレコード(record)から構成される。ヘッダはなくてもよい。ヘッダとレコードの末尾には改行(CRLF)が付く。最終レコードの改行(CRLF)は任意である。
(B) ヘッダ(header)は1つ以上の名前(name)で構成され,カンマ(COMMA)で区切られる。
(C) レコード(record)は一つ以上の項目(field)で構成されており,
(D) 名前(name)は項目(field)である。
(E) 項目(field)はエスケープ(escaped)か,非エスケープ(non-escaped)のいずれかである。
(F) エスケープ(escaped)は,ダブルクォーツで囲まれた0個以上のテキスト文字(TEXTDATA),カンマ(COMMA),改行文字(CRもしくはLF),もしくは2つの連続したダブルクォーツである。
(G) 非エスケープ(non-escaped)は0個以上のテキスト文字(TEXTDATA)である。
(H) コンマは16進数アスキーコード2Cである。
(I) キャリッジリターン(CR)は16進数アスキーコード0Dである。
(J) ダブルクォーツ(DQUOTE)は16進数アスキーコード22である。
(K) ラインフィード(LF)は16進数アスキーコード0Aである。
(L) 改行ラインフィードはキャリッジリターン+ラインフィードである。
(M) テキスト文字(TEXTDATA)は16進数アスキーコードで20〜21,23〜2B,もしくは2D〜7Eである。
Mコマンドでは上記のCSVの定義に対して以下の制約を追加している。
項目数は全行同じでなければならない。
1行の最大長に制限を設ける(デフォルトでは1024000バイト(1MB),10MBまで拡張可能)。
改行はLFのみとする。
最終レコードであっても改行は必須とする。
テキスト文字として80〜FFを付け加える(マルチバイト文字を扱うため)。
利用するCSVファイルが上記の定義を満たしているか確かめるには mchkcsvコマンドを利用すればよい。
多くのMCMDで行われるCSVファイルの入出力の手順は概ね以下に示す手順に従っている。
ファイルからブロック単位でメモリに読み込む。
エスケープ文字を考慮しながらカンマ区切りの項目単位の文字列に分解する。
エスケープ文字を解釈しオリジナルデータに変換する(DQUOTEを外す)。
コマンドの特有の処理を実行し,出力バッファに書き込む。
エスケープが必要であれば,エスケープを付加する。
バッファが一杯になればファイルに出力する。
msortfコマンドを使用して項目の並べ替えを行った場合や、 他のコマンドでs=パラメータ・k=パラメータを使用した場合など、 データがある項目で並べ替えられていることが保証されるとき、 出力されるCSVファイルの項目名には、並べ替えに関する情報が付加される。 具体的には、並べ替え項目として指定した順に%0、%1、…と0から始まる番号が付加される。 数値として並べ替えたときにはnが、降順で並べ替えたときにはrがそれぞれ追加される。
$ msortf i=dat1.csv f=id%n,item o=rsl1.csv #END# kgsortf f=id%n,item i=dat1.csv o=rsl1.csv $ more rsl1.csv id%0n,item%1,price 1,a1,100 2,b1,120 2,b2,200 $ msortf i=dat1.csv f=price%nr o=rsl2.csv #END# kgsortf f=price%nr i=dat1.csv o=rsl2.csv $ more rsl2.csv id,item,price%0nr 2,b2,200 2,b1,120 1,a1,100
msumやmjoinなど多くのコマンドは集計・結合に必要な項目を 自身で並べ替えようとするが、入力ファイルの項目名からあらかじめ 並べ替えられていると判断すれば、その並べ替え処理を省略する。
項目名に並べ替え情報が付加されている場合でも、 f=パラメータ等で指定する場合には省略できる。
$ mcut i=rsl1.csv f=id,item id%0n,item%1 1,a1 2,b1 2,b2
なお、項目名の並べ替え情報と実際のデータの並び順が整合していない場合 (実際には並べ替えられていないのに、項目名に%0が付加されているなど)、 各コマンドの動作は不定となる。
以下にCSVデータで注意すべき点について、例を交えながら説明する。
カンマを含むデータはダブルクォーツで囲われる。 以下は、f1,f2の2項目から構成されるCSVファイルで、0行目1 のf1項目はカンマを含んでいるのでダブルクォーツで囲われている。
f1,f2 "abc,def",2 xyz,2
ダブルクォーツを含むデータはダブルクォーツで囲われ,かつ連続するダブルクォーツとして表現される。 以下は、f1,f2の2項目から構成されるCSVファイルで、 0行目と1行目のf1項目はダブルクォーツを含んでおり、 オリジナルのデータはそれぞれ「abc"def」,「"」である。
f1,f2 "abc""def",2 """",2
改行を含むデータもダブルクオーツで囲うことで処理可能である。 以下の例の0行目のf1項目は、abcの後に改行が含まれているが、ダブルクオーツで囲われているため、 行末ではなくデータの一部として識別される。
f1,f2 "abc def",1
以下のように必要ないデータに対してダブルクオーツを用いていた場合、コマンドの出力時には外される。
$ more data.csv f1,f2 "abc",efg abc,"efg" $ mcut f=f1,f2 i=data.csv f1,f2 abc,efg abc,efg
Footnotes