All Downloads are FREE. Search and download functionalities are using the official Maven repository.

js.prompto.reader.CSVReader.js Maven / Gradle / Ivy


/* we can't use Papa or other js csv libs, because they either load everything in memory or require a continuation */
/* ideally we would use generators, but support with browsers is poor so far */
/* so we use our own stuff until ES6 becomes widespread */

function csvIterate(text, columns, separator, encloser) {
    return new CSVIterator(text, columns, separator, encloser);
}

function csvRead(text, columns, separator, encloser) {
    var list = [];
    var iter = new CSVIterator(text, columns, separator, encloser);
    while(iter.hasNext())
        list.push(iter.next());
    return list;
}

function CSVIterator(text, columns, separator, encloser) {
    this.text = text || null;
    this.index = 0;
    this.columns = columns;
    this.separator = (separator || ',').charCodeAt(0);
    this.encloser = (encloser || '"').charCodeAt(0);
    this.headers = null;
    this.peekedChar = null;
    this.nextChar = 0;
    return this;
}

var DQ = '"'.charCodeAt(0);
var CR = '\r'.charCodeAt(0);
var LF = '\n'.charCodeAt(0);
var ESC = '\\'.charCodeAt(0);

CSVIterator.prototype.hasNext = function() {
    if(this.nextChar==0)
        this.fetchChar(true);
    if(this.headers==null)
        this.parseHeaders();
    return this.nextChar>0;
};



CSVIterator.prototype.fetchChar = function(eatNewLine) {
    eatNewLine = eatNewLine || false;
    if(this.text==null)
        this.nextChar = -1; // EOF
    else if(this.peekedChar!=null) {
        var c = this.peekedChar;
        this.peekedChar = null;
        this.nextChar = c;
    } else {
        var c = this.index < this.text.length ? this.text.charCodeAt(this.index++) : -1;
        if(c==CR)
            this.fetchChar(eatNewLine);
        else if(eatNewLine && (c==LF))
            this.fetchChar(eatNewLine);
        else
            this.nextChar = c;
    }
};

CSVIterator.prototype.peekChar = function() {
    if(this.peekedChar==null) {
        var oldChar = this.nextChar;
        this.fetchChar();
        this.peekedChar = this.nextChar;
        this.nextChar = oldChar;
    }
    return this.peekedChar;
}


CSVIterator.prototype.parseHeaders = function() {
    this.headers = this.parseLine();
    if(this.columns!=null)
        this.headers = this.headers.map(function(header) {
            return this.columns[header] || header;
        }, this);
};

CSVIterator.prototype.parseLine = function() {
    var list = [];
    while(this.parseValue(list))
        ;
    if(this.nextChar==LF)
        this.fetchChar();
    return list;
};

CSVIterator.prototype.parseValue = function(list) {
    if(this.nextChar==this.separator)
        this.parseEmptyValue(list);
    else if(this.nextChar==this.encloser)
        this.parseQuotedValue(list);
    else
        this.parseUnquotedValue(list);
    return this.nextChar!=-1 && this.nextChar!=LF;
};


CSVIterator.prototype.parseEmptyValue = function(list) {
    list.push(null);
    this.fetchChar();
};


CSVIterator.prototype.parseQuotedValue = function(list) {
    this.fetchChar(); // consume the leading double quote
    this.parseValueUpTo(this.encloser, list);
    // look for next sep
    while(this.nextChar!=this.separator && this.nextChar!=-1 && this.nextChar!=LF)
        this.fetchChar();
    if(this.nextChar==this.separator)
        this.fetchChar();
};

CSVIterator.prototype.parseUnquotedValue = function(list) {
    return this.parseValueUpTo(this.separator, list);
};

CSVIterator.prototype.parseValueUpTo = function(endChar, list) {
    var chars = [];
    var exit = false;
    for(;;) {
        if(this.nextChar==-1)
            exit = this.handleEOF(chars, endChar, list);
        else if(this.nextChar==LF)
            exit = this.handleNewLine(chars, endChar, list);
        else if(this.nextChar==endChar)
            exit = this.handleEndChar(chars, endChar, list);
        else if(this.nextChar==ESC)
            exit = this.handleEscape(chars, endChar, list);
        else
            exit = this.handleOtherChar(chars, endChar, list);
        if(exit) {
            if(chars.length>0) {
                chars = chars.map(function(c) {
                    return String.fromCharCode(c);
                });
                list.push(chars.join(""));
            }
            return;
        }
    }
};


CSVIterator.prototype.handleOtherChar = function(chars, endChar, list) {
    chars.push(this.nextChar);
    this.fetchChar();
    return false;
};


CSVIterator.prototype.handleEscape = function(chars, endChar, list) {
    if(this.peekChar()!=-1) {
        chars.push(this.peekChar());
        this.fetchChar();
    }
    this.fetchChar();
    return false;
};


CSVIterator.prototype.handleEOF = function(chars, endChar, list) {
    return true;
}

CSVIterator.prototype.handleEndChar = function(chars, endChar, list) {
    if(endChar==DQ && this.peekChar()==endChar) {
        chars.push(this.nextChar);
        this.fetchChar();
        this.fetchChar();
        return false;
    } else {
        this.fetchChar();
        return true;
    }
};


CSVIterator.prototype.handleNewLine = function(chars, endChar, list) {
    if(endChar==DQ) {
        chars.push(this.nextChar);
        this.fetchChar();
        return false;
    } else {
        return true;
    }
}


CSVIterator.prototype.next = function() {
    if(!this.hasNext()) // will parse headers
        return null;
    var values = this.parseLine();
    var doc = {};
    for(var i=0;i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy