parseRowsWith<R> method
Similar to parseRows, but applies the specified conversion
function to
each row.
See autoType for a convenient row conversion
function that infers and
coerces common types like numbers and strings.
The specified conversion
function is invoked for each row, being passed
an map representing the current row (d), and the index (i) starting at
zero for the first non-header row. If the returned value is null, the row
is skipped and will be omitted from the list returned by parseRowsWith;
otherwise, the returned value defines the corresponding row map. For
example:
final data = csvParseRowsWith(string, (d, _) {
return {
"year": DateTime(int.parse(d[0]), 0, 1), // lowercase and convert "Year" to Date
"make": d[1], // lowercase
"model": d[2], // lowercase
"length": num.parse(d[3]) // lowercase and convert "Length" to number
};
});
In effect, conversion
is similar to applying a List.map and
List.where operator to the returned rows.
Implementation
List<R> parseRowsWith<R>(
String text, R? Function(List<String>, int) conversion) {
var rows = <R>[], // output rows
N = text.length,
I = 0, // current character index
n = 0, // current line number
eof = N <= 0, // current token followed by EOF?
eol = false; // current token followed by EOL?
Object t; // current token
// Strip the trailing newline.
if (N != 0 && text.codeUnitAt(N - 1) == _newline) --N;
if (N != 0 && text.codeUnitAt(N - 1) == _return) --N;
token() {
if (eof) return _eof;
if (eol) {
eol = false;
return _eol;
}
// Unescape quotes.
int i, j = I, c;
if (j < N && text.codeUnitAt(j) == _quote) {
while (++I < N && text.codeUnitAt(I) != _quote ||
++I < N && text.codeUnitAt(I) == _quote) {}
if ((i = I) >= N) {
eof = true;
} else if ((c = text.codeUnitAt(I++)) == _newline) {
eol = true;
} else if (c == _return) {
eol = true;
if (text.codeUnitAt(I) == _newline) ++I;
}
return text.substring(j + 1, i - 1).replaceAll('""', '"');
}
// Find next delimiter or newline.
while (I < N) {
if ((c = text.codeUnitAt(i = I++)) == _newline) {
eol = true;
} else if (c == _return) {
eol = true;
if (text.codeUnitAt(I) == _newline) ++I;
} else if (c != __delimiter) {
continue;
}
return text.substring(j, i);
}
// Return last token before EOF.
eof = true;
return text.substring(j, N);
}
while ((t = token()) != _eof) {
var row = <String>[];
while (t != _eol && t != _eof) {
row.add(t as String);
t = token();
}
var result = conversion(row, n++);
if (result == null) continue;
rows.add(result);
}
return rows;
}