Last active
December 25, 2015 03:29
Revisions
-
JoeRobich revised this gist
Oct 9, 2013 . 1 changed file with 61 additions and 66 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ package com.thedevstop { import flash.events.ErrorEvent; import flash.events.Event; import flash.events.EventDispatcher; import flash.utils.setTimeout; @@ -9,7 +9,8 @@ package com.thedevstop [Event(name="error", type="flash.events.ErrorEvent")] public class CSVReader extends EventDispatcher { private var _hasHeaders:Boolean; private var _lastHeader:String; private var _csv:String; private var _position:int; @@ -18,30 +19,13 @@ package com.thedevstop private var _records:Array; private var _error:Error; public var separator:String = ","; public function getError():Error { return this._error; } public function getHeaders():Array { return this._headers; @@ -52,33 +36,45 @@ package com.thedevstop return this._records; } public function read(csv:String, hasHeaders:Boolean=false):void { this._csv = csv; this._hasHeaders = hasHeaders; this._error = null; this._position = 0; this._headers = []; this._records = []; doLater(continueRead); } private function continueRead():void { try { if (this._hasHeaders && !this._headers.length) readHeader(); else readRecord(); if (atEOF()) onComplete(); else doLater(continueRead); } catch (e:Error) { onError(e); } } private function onComplete():void { this.dispatchEvent(new Event(Event.COMPLETE)); } private function onError(e:Error):void { this._error = e; this.dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); } @@ -90,17 +86,16 @@ package com.thedevstop while (!atEOL() && !atEOF()) { readSeparator(); headerName = readName(); this._headers.push(headerName); } _lastHeader = headerName; if (atEOL()) readEOL(); } private function readRecord():void @@ -109,55 +104,53 @@ package com.thedevstop var fieldIndex:int = 0; var fieldValue:String = readField(); addFieldValue(record, fieldIndex++, fieldValue); while (!atEOL() && !atEOF()) { readSeparator(); fieldValue = readField(); addFieldValue(record, fieldIndex++, fieldValue); } if (!this._hasHeaders) { this._lastHeader = this._headers[this._headers.length - 1]; this._hasHeaders = true; } if (!record.hasOwnProperty(this._lastHeader)) throw new Error("Too few fields on record at position: " + this._position); this._records.push(record); if (atEOL()) readEOL(); } private function addFieldValue(record:Object, fieldIndex:int, fieldValue:String):void { if (fieldIndex >= this._headers.length) { if (this._hasHeaders) throw new Error("Too many fields on record at position: " + this._position); this._headers.push(generateHeaderName(fieldIndex)); } var headerName:String = this._headers[fieldIndex]; record[headerName] = fieldValue; } private function generateHeaderName(fieldIndex:int):String { var a:int = 'A'.charCodeAt(0); var letter:String = String.fromCharCode((fieldIndex % 26) + a); var repeats:int = ((fieldIndex / 26) | 0) + 1; return Array(repeats + 1).join(letter); } private function readName():String { return readField(); @@ -196,9 +189,9 @@ package com.thedevstop continue; } if (atSeparator()) { text += readSeparator(); continue; } @@ -256,15 +249,15 @@ package com.thedevstop return readCharacter() + readCharacter(); } private function atSeparator():Boolean { return peek() == separator; } private function readSeparator():String { if (!atSeparator()) throw Error("Expected Separator at position: " + this._position); return readCharacter(); } @@ -284,10 +277,12 @@ package com.thedevstop private function atTextData():Boolean { if (atSeparator()) return false; var charCode:int = peek().charCodeAt(0); return (charCode >= 0x20 && charCode <= 0x21) || (charCode >= 0x23 && charCode <= 0x7E); } private function readTextData():String -
JoeRobich created this gist
Oct 9, 2013 .There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,375 @@ package com.thedevstop { import flash.events.ErrorEvent; import flash.events.Event; import flash.events.EventDispatcher; import flash.utils.setTimeout; [Event(name="complete", type="flash.events.Event")] [Event(name="error", type="flash.events.ErrorEvent")] public class CSVReader extends EventDispatcher { public var hasHeader:Boolean; private var _csv:String; private var _position:int; private var _headers:Array; private var _records:Array; private var _error:Error; private var _complete:Boolean; public function read(csv:String):void { this._csv = csv; this._error = null; this._complete = false; this._position = 0; this._headers = []; this._records = []; doLater(continueRead); } public function getError():Error { return this._error; } public function getComplete():Boolean { return this._complete; } public function getHeaders():Array { return this._headers; } public function getRecords():Array { return this._records; } private function continueRead():void { try { if (this.hasHeader && !this._headers.length) readHeader(); else readRecord(); if (!this._complete) doLater(continueRead); } catch (e:Error) { error(e); } } private function complete():void { this._complete = true; this.dispatchEvent(new Event(Event.COMPLETE)); } private function error(e:Error):void { this._complete = true; this._error = e; this.dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); } private function readHeader():void { var headerName:String = readName(); this._headers.push(headerName); while (!atEOL() && !atEOF()) { readComma(); headerName = readName(); this._headers.push(headerName); } if (atEOL()) readEOL(); if (atEOF()) complete(); } private function readRecord():void { var record:Object = { }; var fieldIndex:int = 0; var fieldValue:String = readField(); addFieldValue(record, fieldIndex, fieldValue); while (!atEOL() && !atEOF()) { readComma(); fieldIndex++; fieldValue = readField(); addFieldValue(record, fieldIndex, fieldValue); } if (!record.hasOwnProperty(this._headers[this._headers.length - 1])) throw new Error("Too few fields on row at position: " + this._position); this._records.push(record); if (!this.hasHeader) this.hasHeader = true; if (atEOL()) readEOL(); if (atEOF()) complete(); } private function addFieldValue(record:Object, fieldIndex:int, fieldValue:String):void { var headerName:String; if (fieldIndex < this._headers.length) { headerName = this._headers[fieldIndex]; } else { if (this.hasHeader) throw new Error("Too many fields on row at position: " + this._position); var a:int = 'A'.charCodeAt(0); var letter = String.fromCharCode((fieldIndex % 26) + a); var repeats = ((fieldIndex / 26) | 0) + 1; headerName = Array(repeats + 1).join(letter); this._headers.push(headerName); } record[headerName] = fieldValue; } private function readName():String { return readField(); } private function readField():String { eatWhiteSpace(); if (atEOL() || atEOF()) throw Error("Expected Field at position: " + this._position); var field:String; if (atDoubleQuote()) field = readEscaped(); else field = readNonEscaped(); eatWhiteSpace(); return field; } private function readEscaped():String { var text:String = ""; readDoubleQuote(); while(true) { if (atTextData()) { text += readTextData(); continue; } if (atComma()) { text += readComma(); continue; } if (atCarriageReturn()) { text += readCarriageReturn(); continue; } if (atLineFeed()) { text += readLineFeed(); continue; } if (atTwoDoubleQuotes()) { text += readTwoDoubleQuotes(); continue; } break; } readDoubleQuote(); return text; } private function readNonEscaped():String { var text:String = ""; while (atTextData()) text += readTextData(); return text; } private function atEOF():Boolean { return this._position == this._csv.length; } private function atEOL():Boolean { return peek() == "\r" && peekNext() == "\n"; } private function readEOL():String { if (!atEOL()) throw Error("Expected EOL at position: " + this._position); return readCharacter() + readCharacter(); } private function atComma():Boolean { return peek() == ","; } private function readComma():String { if (!atComma()) throw Error("Expected Comma at position: " + this._position); return readCharacter(); } private function atDoubleQuote():Boolean { return peek() == '"'; } private function readDoubleQuote():String { if (!atDoubleQuote()) throw Error("Expected DoubleQuote at position: " + this._position); return readCharacter(); } private function atTextData():Boolean { var charCode:int = peek().charCodeAt(0); return (charCode >= 0x20 && charCode <= 0x21) || (charCode >= 0x23 && charCode <= 0x2B) || (charCode >= 0x2D && charCode <= 0x7E); } private function readTextData():String { if (!atTextData()) throw Error("Expected TextData at position: " + this._position); return readCharacter(); } private function atCarriageReturn():Boolean { return peek() == "\r"; } private function readCarriageReturn():String { if (!atCarriageReturn()) throw Error("Expected CarriageReturn at position: " + this._position); return readCharacter(); } private function atLineFeed():Boolean { return peek() == "\n"; } private function readLineFeed():String { if (!atLineFeed()) throw Error("Expected LineFeed at position: " + this._position); return readCharacter(); } private function atTwoDoubleQuotes():Boolean { return peek() == '"' && peekNext() == '"'; } private function readTwoDoubleQuotes():String { if (!atTwoDoubleQuotes()) throw Error("Expected TwoDoubleQuotes at position: " + this._position); readCharacter(); return readCharacter(); } private function peek():String { return this._csv.charAt(this._position); } private function peekNext():String { if (this._position + 1 == this._csv.length) return ""; return this._csv.charAt(this._position + 1); } private function readCharacter():String { return this._csv.charAt(this._position++); } private function atWhiteSpace():Boolean { return peek() == " " || peek() == "\t"; } private function eatWhiteSpace():void { while (atWhiteSpace()) readCharacter(); } private function doLater(func:Function):void { setTimeout(func, 1); } } }