nadesiko3
Version:
Japanese Programming Language
187 lines (186 loc) • 5.19 kB
JavaScript
export const options = {
delimiter: ',',
eol: '\r\n'
};
export function resetEnv() {
options.delimiter = ',';
options.eol = '\r\n';
}
export function parse(txt, delimiter = undefined) {
// delimiter
if (delimiter === undefined) {
delimiter = options.delimiter;
}
// check txt
txt = '' + txt + '\n';
// convert CRLF to LF, and CR to LF
txt = txt.replace(/(\r\n|\r)/g, '\n');
// trim right
txt = txt.replace(/\s+$/, '') + '\n';
// set pattern
const patToDelim = '^(.*?)([\\' + delimiter + '\\n])';
const reToDelim = new RegExp(patToDelim);
// if value is number then convert to float
const convType = function (v) {
if (typeof (v) === 'string') {
if (v.search(/^[0-9.]+$/) >= 0) {
v = parseFloat(v); // convert number
}
}
return v;
};
// parse txt
const res = [];
let cells = [];
let c = '';
while (txt !== '') {
// first check delimiter (because /^\s+/ skip delimiter'\t') (#3)
c = txt.charAt(0);
if (c === delimiter) {
txt = txt.substring(1);
cells.push('');
continue;
}
// second check LF (#7)
if (c === '\n') {
cells.push('');
res.push(cells);
cells = [];
txt = txt.substring(1);
continue;
}
// trim white space
txt = txt.replace(/^\s+/, '');
c = txt.charAt(0);
// no data
if (c === delimiter) {
console.log('delimiter');
cells.push('');
txt = txt.substring(delimiter.length);
continue;
}
// written using the dialect of Excel
if (c === '=' && txt.charAt(1) === '"') {
txt = txt.substring(1);
continue;
}
// number or simple string
if (c !== '"') { // number or simple str
const m = reToDelim.exec(txt);
if (!m) {
cells.push(convType(txt));
res.push(cells);
cells = [];
break;
}
if (m[2] === '\n') {
cells.push(convType(m[1]));
res.push(cells);
cells = [];
}
else if (m[2] === delimiter) {
cells.push(convType(m[1]));
}
txt = txt.substring(m[0].length);
continue;
}
// "" ... blank data
if (txt.substring(0, 2) === '""') {
cells.push('');
txt = txt.substring(2);
continue;
}
// "..."
let i = 1;
let s = '';
while (i < txt.length) {
const c1 = txt.charAt(i);
const c2 = txt.charAt(i + 1);
// console.log("@" + c1 + c2);
// 2quote => 1quote char
if (c1 === '"' && c2 === '"') {
i += 2;
s += '"';
continue;
}
if (c1 === '"') {
i++;
if (c2 === delimiter) {
i++;
cells.push(convType(s));
s = '';
break;
}
if (c2 === '\n') {
i++;
cells.push(convType(s));
res.push(cells);
cells = [];
break;
}
// if (c2 === " " || c2 === "\t") {
i++;
continue;
}
s += c1;
i++;
}
txt = txt.substr(i);
}
if (cells.length > 0)
res.push(cells);
return res;
}
// convert 2D array to CSV string
export function stringify(ary, delimiter = undefined, eol = undefined) {
// check arguments
if (delimiter === undefined) {
delimiter = options.delimiter;
}
if (eol === undefined) {
eol = options.eol;
}
const valueConv = genValueConverter(delimiter);
if (ary === undefined)
return '';
let r = '';
for (let i = 0; i < ary.length; i++) {
const cells = ary[i];
if (cells === undefined) {
r += eol;
continue;
}
for (let j = 0; j < cells.length; j++) {
cells[j] = valueConv(cells[j]);
}
r += cells.join(delimiter) + eol;
}
// replace return code
r = r.replace(/(\r\n|\r|\n)/g, eol);
return r;
}
export function replaceEolMark(eol) {
eol = eol.replace(/\n\r/g, '[CRLF]');
eol = eol.replace(/\r/g, '[CR]');
eol = eol.replace(/\n/g, '[LF]');
return eol;
}
function genValueConverter(delimiter) {
return function (s) {
s = '' + s;
let fQuot = false;
if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) {
fQuot = true;
}
if (s.indexOf(delimiter) >= 0) {
fQuot = true;
}
if (s.indexOf('"') >= 0) {
fQuot = true;
s = s.replace(/"/g, '""');
}
if (fQuot)
s = '"' + s + '"';
return s;
};
}