Skip to content

Instantly share code, notes, and snippets.

@gerardpaapu
Created August 24, 2015 01:55
Show Gist options
  • Save gerardpaapu/d076de8fcb079fce9f33 to your computer and use it in GitHub Desktop.
Save gerardpaapu/d076de8fcb079fce9f33 to your computer and use it in GitHub Desktop.
function makeCSVReader(records, opts) {
'use strict';
function noop() {}
function createRecordConstructor(fields) {
var src = '';
for (var i = 0; i < fields.length; i++) {
src += 'this[' + JSON.stringify(fields[i]) + '] = fields[' + i + '];\n';
}
// EVAL, EVAL, EVAL
return new Function('fields', src);
}
var state = 1;
var fields = [];
var Record = null;
var field = [];
var onClose = opts.onClose || noop;
opts = opts || {};
function terminateField() {
fields[fields.length] = field.join('');
field = [];
}
function terminateRecordWithHeader() {
terminateField();
if (Record == null) {
Record = createRecordConstructor(fields);
} else {
records.push(new Record(fields));
}
fields = [];
}
function terminateRecordWithoutHeader() {
terminateField();
records.push(fields);
fields = [];
}
var terminateRecord = opts.header ?
terminateRecordWithHeader :
terminateRecordWithoutHeader;
var COMMA = ',';
var CR = '\r';
var LF = '\n';
var DOUBLE_QUOTE = '"';
var CTX_FIELD_START = 1;
var CTX_IN_FIELD = 2;
var CTX_IN_QUOTED_FIELD = 3;
var CTX_ON_QUOTE = 4;
var CTX_ON_CR = 5;
var EXPECTED_LINE_FEED = -1;
var EXPECTED_FIELD_TERMINATOR = -2;
return function readString(str) {
if (str == null) {
terminateRecord();
onClose();
return 0;
}
for (var i = 0; i < str.length; i++) {
var char = str[i];
switch (state) {
case CTX_FIELD_START:
if (char === DOUBLE_QUOTE) {
state = CTX_IN_QUOTED_FIELD;
} else {
field = [char];
state = CTX_IN_FIELD;
}
break;
case CTX_IN_FIELD:
if (char === CR) {
terminateRecord();
state = CTX_ON_CR;
} else if (char === LF) {
terminateRecord();
state = CTX_FIELD_START;
} else if (char === COMMA) {
terminateField();
state = CTX_FIELD_START;
} else {
field[field.length] = char;
}
break;
case CTX_IN_QUOTED_FIELD:
if (char === DOUBLE_QUOTE) {
state = CTX_ON_QUOTE;
} else {
field[field.length] = char;
}
break;
case CTX_ON_QUOTE:
if (char === DOUBLE_QUOTE) {
field[field.length] = char;
state = CTX_IN_QUOTED_FIELD;
} else if (char === COMMA) {
terminateField();
state = CTX_FIELD_START;
} else if (char === CR) {
terminateRecord();
state = CTX_ON_CR;
} else {
return EXPECTED_FIELD_TERMINATOR;
}
break;
case CTX_ON_CR:
if (char !== LF) {
return EXPECTED_LINE_FEED;
}
state = CTX_FIELD_START;
break;
}
}
return str.length;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment