A friend of mine wanted an array-to-CSV string function for Node.js, so I came up with this. Basically, it can take in a single object, a 2D array or an array of objects.
If the children or parent is an object then the object properties become the headers, if the children are arrays then the first array is the headers.
Each cell is enclosed inside double quotes in the case of commas inside of the cell, and any double quotes inside the cell are escaped. Is there anything else I should be escaping?
exports.objectToCSVString = function (ob) {
var str = "", row, a, i, o, c, r;
if(ob instanceof Object && !(ob instanceof Array)){
ob = [ob];
}
if(ob instanceof Array){
for(r in ob){
if(ob.hasOwnProperty(r)){
row = ob[r];
if(row instanceof Array){
a = "";
for(i in row){
if(row.hasOwnProperty(i)){
a += a.length === 0 ? "" : ",";
a += "\"" + row[i].toString().replaceAll("\"", "\\\"") + "\"";
}
}
str += str.length === 0 ? a : "\r\n" + a;
}else if(row instanceof Object){
if(o === undefined){
o = [];
a = "";
for(c in row){
if(row.hasOwnProperty(c)){
o.push(c);
a += a.length === 0 ? "" : ",";
a += "\"" + c.toString().replaceAll("\"", "\\\"") + "\"";
}
}
str += str.length === 0 ? a : "\r\n" + a;
}
a = "";
for(c in o){
if(o.hasOwnProperty(c) && row[o[c]] !== undefined){
a += a.length === 0 ? "" : ",";
a += "\"" + row[o[c]].toString().replaceAll("\"", "\\\"") + "\"";
}
}
str += str.length === 0 ? a : "\r\n" + a;
}else{
throw "row is not an Array or object";
}
}
}
return str;
}
throw "Object is not an Array";
};
String.prototype.replaceAll = function(a, b){
var t = this, o = [], i;
//get all the occurances of it
for(i = 0; i < t.length; i+=1){
if(t.substr(i, i - 1 + a.length) == a){
o.push(i);
}
}
for(i = 0; i < o.length; i+=1){
t = t.substr(0, o[i] - 1) + b + t.substr(o[i] + b.length, t.length - 1);
}
return t;
};
Is the concept right? Do I cover everything when it comes to creating a CSV string? Any other comments?
Is there any way I can improve this or improve the performance? It seems to be rather quick when running, but I'm not sure what to base it on either.
Examples
Given I have required the file and it is names csv
csv.objectToCSVString({a:"a1",b:"b1"});
will output:
"a", "b"
"a1", "b1"
csv.objectToCSVString([{a:"a1",b:"b1"},{a:"a2",b:"b2"}]);
will output:
"a","b"
"a1","b1"
"a2","b2"
csv.objectToCSVString([["a", "b"], ["a1", "b1"], ["a2", "b2"]]);
will output:
"a","b"
"a1","b1"
"a2","b2"
csv.objectToCSVString({a:"a\"1\"",b:"b\"1\""});
will output:
"a","b"
"a\"1\"","b\"1\""
NOTE I am working on the replace all function, it doesn't work as it should yet