| 1 |
/** |
|---|
| 2 |
* Excel 準拠の CSV ファイルを配列変数に変換するクラス |
|---|
| 3 |
*/ |
|---|
| 4 |
|
|---|
| 5 |
package com.kujirahand |
|---|
| 6 |
{ |
|---|
| 7 |
import mx.collections.ArrayCollection; |
|---|
| 8 |
|
|---|
| 9 |
/** |
|---|
| 10 |
* CSV ファイル(Excel準拠)のテキストを、Array や ArrayCollection に変換するもの。 |
|---|
| 11 |
* @author クジラ飛行机(http://kujirahand.com) |
|---|
| 12 |
* @langversion ActionScript 3.0 |
|---|
| 13 |
* @example CSV形式のテキストを配列に変換する |
|---|
| 14 |
* <listing version="3.0" > |
|---|
| 15 |
* var csv_str = "name, value\naaa,30\nbbbb,50\ncccc,30\n"; |
|---|
| 16 |
* var csv_ary:Array = CSVUtils.CsvToArray(csv_str); // CSV→Array |
|---|
| 17 |
* trace( CSVUtils.ArrayToCsv(csv_ary) ); // Array→CSV |
|---|
| 18 |
* </listing> |
|---|
| 19 |
* @example DataGrid に CSVテキストを表示する |
|---|
| 20 |
* <listing version="3.0" > |
|---|
| 21 |
* // <mx:DataGrid id="data_grid"> |
|---|
| 22 |
* // <mx:DataGridColumn dataField="name"/> |
|---|
| 23 |
* // <mx:DataGridColumn dataField="tel"/> |
|---|
| 24 |
* // <mx:DataGridColumn dataField="memo"/> |
|---|
| 25 |
* // </mx:DataGrid> |
|---|
| 26 |
* var csv_str = "name, tel, memo\naaa,03-xxx-xxxx,memo\nbbbb,03-xxx-xxxx\n"; |
|---|
| 27 |
* var csv_ary:Array = CSVUtils.CsvToArray(csv_str); // CSV→Array |
|---|
| 28 |
* var mapping:Array = ['name', 'tel', 'memo']; |
|---|
| 29 |
* var csv_ac:ArrayCollection; |
|---|
| 30 |
* csv_ac = CSVUtils.ArrayToArrayCollection(csv_ary, mapping, true); |
|---|
| 31 |
* data_grid.dataProvider = csv_ac; // set to DataGrid |
|---|
| 32 |
* </listing> |
|---|
| 33 |
* @see http://www.libspark.org/wiki/kujirahand/CSVUtils WIKI |
|---|
| 34 |
* @see http://www.libspark.org/browser/as3/CSVUtils/src/com/kujirahand/CSVUtils.as 最新版ダウンロード(SVNリポジトリ) |
|---|
| 35 |
* @see http://kujirahand.com/as3/com/kujirahand/CSVUtils.html ASDoc |
|---|
| 36 |
*/ |
|---|
| 37 |
public class CSVUtils |
|---|
| 38 |
{ |
|---|
| 39 |
// 静的メソッド |
|---|
| 40 |
/** CSV の列の区切り記号(1文字のみ対応) */ |
|---|
| 41 |
public static var DEFAULT_SPLITTER:String = ","; |
|---|
| 42 |
/** 行の区切り記号は \n で固定 */ |
|---|
| 43 |
public static const LINE_SPLLITER:String = "\n"; |
|---|
| 44 |
|
|---|
| 45 |
/** CSV を配列に変換する関数 |
|---|
| 46 |
* @param csv_str CSV文字列 |
|---|
| 47 |
* @return 二次元配列変数 |
|---|
| 48 |
*/ |
|---|
| 49 |
public static function CsvToArray(csv_str:String):Array { |
|---|
| 50 |
return CsvToArray_spl(csv_str, DEFAULT_SPLITTER); |
|---|
| 51 |
} |
|---|
| 52 |
|
|---|
| 53 |
/** |
|---|
| 54 |
* TSVを配列に変換する関数 |
|---|
| 55 |
* @param tsv_str TSV文字列 |
|---|
| 56 |
* @return 二次元配列変数 |
|---|
| 57 |
*/ |
|---|
| 58 |
public static function TsvToArray(tsv_str:String):Array { |
|---|
| 59 |
return CsvToArray_spl(tsv_str, "\t"); |
|---|
| 60 |
} |
|---|
| 61 |
|
|---|
| 62 |
/** 任意の区切り記号のCSVを配列に変換する関数 */ |
|---|
| 63 |
public static function CsvToArray_spl(csv_str:String, splitter:String):Array { |
|---|
| 64 |
var csv:CSVUtils = new CSVUtils(); |
|---|
| 65 |
return csv.split(csv_str, splitter); |
|---|
| 66 |
} |
|---|
| 67 |
|
|---|
| 68 |
public static function replaceStr(str:String, a:String, b:String):String { |
|---|
| 69 |
var o:Array = str.split(a); |
|---|
| 70 |
return o.join(b); |
|---|
| 71 |
} |
|---|
| 72 |
/** |
|---|
| 73 |
* CSVファイルをデータグリッドに表示するために、ArrayCollectionに変換する |
|---|
| 74 |
* @param csv_ary 二次元配列変数 |
|---|
| 75 |
* @param mapping マッピングするフィールド名の配列 |
|---|
| 76 |
* @param topline_is_header 1行目をヘッダとして利用しているなら true にすると削る |
|---|
| 77 |
* @return 変換された ArrayCollection |
|---|
| 78 |
*/ |
|---|
| 79 |
public static function ArrayToArrayCollection(csv_ary:Array, |
|---|
| 80 |
mapping:Array, topline_is_header:Boolean = false):ArrayCollection { |
|---|
| 81 |
if (topline_is_header) { // 1行目をヘッダとして使うなら削る |
|---|
| 82 |
csv_ary.splice(0, 1); |
|---|
| 83 |
} |
|---|
| 84 |
var result_ary:ArrayCollection = new ArrayCollection(); |
|---|
| 85 |
for (var row:int = 0; row < csv_ary.length; row++) { |
|---|
| 86 |
var cols:Array = csv_ary[row]; |
|---|
| 87 |
var col_obj:Object = {}; |
|---|
| 88 |
for (var col:int = 0; col < mapping.length; col++) { |
|---|
| 89 |
var field_name:String = mapping[col]; |
|---|
| 90 |
var col_str:String = cols[col]; |
|---|
| 91 |
if (field_name == ""||field_name == null) continue; |
|---|
| 92 |
col_obj[field_name] = col_str; |
|---|
| 93 |
} |
|---|
| 94 |
result_ary.addItem(col_obj); |
|---|
| 95 |
} |
|---|
| 96 |
return result_ary; |
|---|
| 97 |
} |
|---|
| 98 |
/** |
|---|
| 99 |
* 二次元配列をCSV形式に変換する |
|---|
| 100 |
* @param csv_ary 配列変数 |
|---|
| 101 |
* @param splitter 区切り記号 |
|---|
| 102 |
* @param use_escape 必ず ダブルコーテーションで囲う場合 |
|---|
| 103 |
* @return CSV形式の文字列 |
|---|
| 104 |
*/ |
|---|
| 105 |
public static function ArrayToCsv(csv_ary:Array, splitter:String, |
|---|
| 106 |
use_escape:Boolean = false):String { |
|---|
| 107 |
var res:String = ""; |
|---|
| 108 |
for (var row:int = 0; row < csv_ary.length; row++) { |
|---|
| 109 |
var cols:Array = csv_ary[row]; |
|---|
| 110 |
for (var col:int = 0; col < cols.length; col++) { |
|---|
| 111 |
var cell:String = cols[col]; |
|---|
| 112 |
if (use_escape || hasEscapeChar(cell, splitter)) { |
|---|
| 113 |
cell = escapeCell(cell); |
|---|
| 114 |
} |
|---|
| 115 |
res += cell + splitter; |
|---|
| 116 |
} |
|---|
| 117 |
if (cols.length > 0) res = res.substr(0, res.length -1); |
|---|
| 118 |
res += LINE_SPLLITER; |
|---|
| 119 |
} |
|---|
| 120 |
if (csv_ary.length > 0) res = res.substr(0, res.length - 1); |
|---|
| 121 |
return res; |
|---|
| 122 |
} |
|---|
| 123 |
/** |
|---|
| 124 |
* 文字列を ".." で括る必要があるかチェックする |
|---|
| 125 |
*/ |
|---|
| 126 |
public static function hasEscapeChar(cell:String, splitter:String):Boolean { |
|---|
| 127 |
if (cell.indexOf('"') >= 0) return true; |
|---|
| 128 |
if (cell.indexOf("\n") >= 0) return true; |
|---|
| 129 |
if (cell.indexOf("\r") >= 0) return true; |
|---|
| 130 |
if (cell.indexOf("\t") >= 0) return true; |
|---|
| 131 |
if (cell.indexOf(" ") >= 0) return true; |
|---|
| 132 |
if (cell.indexOf(splitter) >= 0) return true; |
|---|
| 133 |
return false; |
|---|
| 134 |
} |
|---|
| 135 |
/** |
|---|
| 136 |
* CSVのセル(文字列)を ".." で括ってエスケープする |
|---|
| 137 |
*/ |
|---|
| 138 |
public static function escapeCell(cell:String):String { |
|---|
| 139 |
cell = replaceStr(cell, '"', '""'); |
|---|
| 140 |
cell = '"' + cell + '"'; |
|---|
| 141 |
return cell; |
|---|
| 142 |
} |
|---|
| 143 |
// ------------------ |
|---|
| 144 |
// CSVUtils クラス |
|---|
| 145 |
private var csv_str:String; |
|---|
| 146 |
private var splitter:String; |
|---|
| 147 |
private var index:int; |
|---|
| 148 |
|
|---|
| 149 |
public function split(csv_str:String, splitter:String):Array { |
|---|
| 150 |
// 改行を統一する |
|---|
| 151 |
csv_str = replaceStr(csv_str, "\r\n", LINE_SPLLITER); |
|---|
| 152 |
csv_str = replaceStr(csv_str, "\r", LINE_SPLLITER); |
|---|
| 153 |
// |
|---|
| 154 |
this.csv_str = csv_str; |
|---|
| 155 |
this.splitter = splitter; |
|---|
| 156 |
// |
|---|
| 157 |
return splitLoop(); |
|---|
| 158 |
} |
|---|
| 159 |
private function splitLoop():Array { |
|---|
| 160 |
var result:Array = []; |
|---|
| 161 |
while (csv_str.length > 0) { |
|---|
| 162 |
var cols:Array = getCols(); |
|---|
| 163 |
result.push(cols); |
|---|
| 164 |
} |
|---|
| 165 |
return result; |
|---|
| 166 |
} |
|---|
| 167 |
private function getCols():Array { |
|---|
| 168 |
var cols:Array = []; |
|---|
| 169 |
index = 0; |
|---|
| 170 |
while (index < csv_str.length) { |
|---|
| 171 |
var c:String = csv_str.charAt(index); |
|---|
| 172 |
var col:String; |
|---|
| 173 |
if (c == LINE_SPLLITER) { |
|---|
| 174 |
index++; |
|---|
| 175 |
break; |
|---|
| 176 |
} |
|---|
| 177 |
if (c == '"') { |
|---|
| 178 |
col = getColStr(); |
|---|
| 179 |
} |
|---|
| 180 |
else { |
|---|
| 181 |
col = getColSimple(); |
|---|
| 182 |
} |
|---|
| 183 |
skipSpace(); |
|---|
| 184 |
cols.push(col); |
|---|
| 185 |
} |
|---|
| 186 |
// 切り取る |
|---|
| 187 |
csv_str = csv_str.substr(index); |
|---|
| 188 |
return cols; |
|---|
| 189 |
} |
|---|
| 190 |
private function getColSimple():String { |
|---|
| 191 |
var col:String = ""; |
|---|
| 192 |
while (index < csv_str.length) { |
|---|
| 193 |
if (csv_str.substr(index, 2) == '""') { |
|---|
| 194 |
col += '"'; |
|---|
| 195 |
index += 2; |
|---|
| 196 |
continue; |
|---|
| 197 |
} |
|---|
| 198 |
var c:String = csv_str.charAt(index); |
|---|
| 199 |
if (c == splitter) { |
|---|
| 200 |
index++; |
|---|
| 201 |
break; |
|---|
| 202 |
} |
|---|
| 203 |
if (c == LINE_SPLLITER) { |
|---|
| 204 |
break; |
|---|
| 205 |
} |
|---|
| 206 |
col += c; |
|---|
| 207 |
index++; |
|---|
| 208 |
} |
|---|
| 209 |
return col; |
|---|
| 210 |
} |
|---|
| 211 |
private function getColStr():String { |
|---|
| 212 |
// "str" の文字列 |
|---|
| 213 |
index++; // skip '"' |
|---|
| 214 |
var col:String = ""; |
|---|
| 215 |
while (index < csv_str.length) { |
|---|
| 216 |
if (csv_str.substr(index, 2) == '""') { |
|---|
| 217 |
col += '"'; |
|---|
| 218 |
index += 2; |
|---|
| 219 |
continue; |
|---|
| 220 |
} |
|---|
| 221 |
var c:String = csv_str.charAt(index); |
|---|
| 222 |
if (c == '"') { // 終端 '"' の可能性 |
|---|
| 223 |
index++; |
|---|
| 224 |
skipSpace(); |
|---|
| 225 |
// 終端のはず、もし違えば、壊れた形式の可能性があるが継続する |
|---|
| 226 |
if (csv_str.charAt(index) == ",") { |
|---|
| 227 |
index++; |
|---|
| 228 |
} |
|---|
| 229 |
break; |
|---|
| 230 |
} |
|---|
| 231 |
col += c; |
|---|
| 232 |
index++; |
|---|
| 233 |
} |
|---|
| 234 |
return col; |
|---|
| 235 |
} |
|---|
| 236 |
private function skipSpace():void { |
|---|
| 237 |
if (csv_str.charAt(index) == " ") { |
|---|
| 238 |
index++; |
|---|
| 239 |
} |
|---|
| 240 |
} |
|---|
| 241 |
} |
|---|
| 242 |
} |
|---|
| 243 |
|
|---|