-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcsv.js
More file actions
105 lines (87 loc) · 1.81 KB
/
csv.js
File metadata and controls
105 lines (87 loc) · 1.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"use strict";
function parseCsv(text) {
if (text.charCodeAt(0) === 0xfeff) {
text = text.slice(1);
}
const rows = [];
let row = [];
let field = "";
let inQuotes = false;
for (let i = 0; i < text.length; i += 1) {
const ch = text[i];
if (inQuotes) {
if (ch === '"') {
if (text[i + 1] === '"') {
field += '"';
i += 1;
} else {
inQuotes = false;
}
} else {
field += ch;
}
continue;
}
if (ch === '"') {
inQuotes = true;
continue;
}
if (ch === ",") {
row.push(field);
field = "";
continue;
}
if (ch === "\n") {
row.push(field);
rows.push(row);
row = [];
field = "";
continue;
}
if (ch === "\r") {
if (text[i + 1] === "\n") {
i += 1;
}
row.push(field);
rows.push(row);
row = [];
field = "";
continue;
}
field += ch;
}
row.push(field);
rows.push(row);
if (rows.length && rows[rows.length - 1].length === 1 && rows[rows.length - 1][0] === "") {
rows.pop();
}
const headers = rows.shift() || [];
const dataRows = rows.map((r) => {
const obj = {};
for (let i = 0; i < headers.length; i += 1) {
obj[headers[i]] = r[i] ?? "";
}
return obj;
});
return { headers, rows: dataRows };
}
function stringifyCsv(rows, headers) {
const lines = [];
lines.push(headers.join(","));
for (const row of rows) {
const fields = headers.map((h) => escapeCsvField(row[h] ?? ""));
lines.push(fields.join(","));
}
return `${lines.join("\n")}\n`;
}
function escapeCsvField(value) {
const str = String(value);
if (/[",\n\r]/.test(str)) {
return `"${str.replace(/"/g, '""')}"`;
}
return str;
}
export {
parseCsv,
stringifyCsv,
};