blob: ab2f0be6854dc89913b335f4d65d551cb7900098 (
plain)
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
|
/// A minimal RFC 4180 reader, for the `/csv` batch endpoint.
///
/// Values may contain commas and are then double-quoted with `""` escaping, so
/// splitting on `,` corrupts every row that carries a street name like
/// `Rua Um, Dois`. This is here because the Dart SDK ships no CSV parser and
/// this library keeps its dependency list to one entry.
library;
const String _bom = '\u{FEFF}';
/// Parses CSV text into records keyed by its header row.
///
/// A leading byte-order mark is dropped, `CRLF` and `LF` are both accepted, and
/// a row shorter than the header has its remaining columns filled with the
/// empty string. An empty input yields no records.
List<Map<String, String>> parseCsv(String text) {
final rows = _parseRows(text.startsWith(_bom) ? text.substring(1) : text);
if (rows.isEmpty) {
return <Map<String, String>>[];
}
final header = rows.removeAt(0);
final records = <Map<String, String>>[];
for (final row in rows) {
if (row.length == 1 && row.first.isEmpty) {
continue;
}
final record = <String, String>{};
for (var i = 0; i < header.length; i++) {
record[header[i]] = i < row.length ? row[i] : '';
}
records.add(record);
}
return records;
}
List<List<String>> _parseRows(String text) {
final rows = <List<String>>[];
final field = StringBuffer();
var row = <String>[];
var quoted = false;
var started = false;
for (var i = 0; i < text.length; i++) {
final char = text[i];
if (quoted) {
if (char == '"') {
if (i + 1 < text.length && text[i + 1] == '"') {
field.write('"');
i++;
} else {
quoted = false;
}
} else {
field.write(char);
}
continue;
}
if (char == '"') {
quoted = true;
started = true;
} else if (char == ',') {
row.add(field.toString());
field.clear();
started = true;
} else if (char == '\n') {
row.add(field.toString());
field.clear();
rows.add(row);
row = <String>[];
started = false;
} else if (char != '\r') {
field.write(char);
started = true;
}
}
if (started || field.isNotEmpty || row.isNotEmpty) {
row.add(field.toString());
rows.add(row);
}
return rows;
}
|