CSVをちゃんと読む Flash/JavaScript
FlashでCSVファイルを読む必要があったので、使えるものがないかFlashとCSVでググってみたところ…
var lines = text.split("\n"); var sheet = []; for(var i = 0; i < lines.length; i++) { sheet.push(line.split(","))); }
なんじゃこりゃ。こんな感じのばっかり。これ
http://ja.wikipedia.org/wiki/Comma-Separated_Values
とかこれ
http://www.kasai.fm/wiki/rfc4180jp
とか読め、と。
というわけで、ECMAなスクリプトでまともにCVS解釈ルーチンを書きました。FlashのAS1(ECMAサブセット)でも動きます。
RFCの仕様は満たし、かつ、仕様漏れのあるところはOpenOfficeのCSV解釈に準拠しています。
/* * CSV parser. * * result of this function can be used like "csv[row][col]". * all rows has the same number of columns. * * @param src raw string of CSV format * @return an Array(2D) */ function parseCSV(src) { // constants var QUOT = '"', SEP = ',', CR = "\r", LF = "\n"; // data to be generated var sheet = [], row = [], cell = ""; // status flags var inquot = false; // true when the current cell starts with quot. var cn = src.charAt(0); // the next character, to be the 1st one before scanning. for (var i = 0; i < src.length; i++) { var cc = cn; // current character is the next character of previous loop. cn = (i == src.length - 1) ? null : src.charAt(i + 1); // the next character if (cc == CR) { if (cn != LF) cc = LF; // CR without LF : considerd as LF if (cn == LF) continue; // CR with LF : skip this CR } if (inquot) { // put a character to current cell with quot character escape if ... // current cell starts with quot and // now quoted string is still not terminated. // - double quot: puts a quot, then progress cursor twice. // - single quot: ends this mode. // - else : put a character to current cell. switch(cc) { case QUOT: if (cn == QUOT) { cell += QUOT; i++; } else inquot = false; break; default: cell += cc; } } else { // put a character to current cell or move to the next cell/row if ... // current cell does still not start, // starts without quot or // quot terminated in cell. // - newline : ends current row. // - comma : ends current cell. // - 1st quot : starts quoted cell. (it would be happen with the 1st character of cell.) // - else : put a character to current cell. switch(cc) { case LF: row.push(cell); cell = ""; sheet.push(row); row = []; break; case SEP: row.push(cell); cell = ""; break; case QUOT: if (cell == "") { inquot = true; break; } default: cell += cc; } } } // join characters after the last spearator to this sheet. if(cell != "") row.push(cell); if(row.length > 0) sheet.push(row); // adjust number of columns of each rows. var cols = 0; // the max length of each row for (i = 0; i < sheet.length; i++) { cols = Math.max(sheet[i].length, cols); } for (i = 0; i < sheet.length; i++) { var pad = cols - sheet[i].length; // count to be padded. for (j = 0; j < pad; j++) { sheet[i].push(""); } } return sheet; }
CR+LFのファイルで、末尾行の末尾列がクォート閉じなかった場合、CRが混入するかどうかが違うぐらい。英語コメントが変な文章だけど、そこはご愛嬌で(^^;
保存してあるCSVファイルの文字エンコーディングには注意しましょう。言語機能の特性上、PHPみたいに、外部テキストの文字コード変換ができないので。(それにしても、FlashのSystem.useCodePageはひどい。非同期APIでシングルトンにフラグを持たせるとは…)