parseRowsWith<R> method

List<R> parseRowsWith<R>(
  1. String text,
  2. R? conversion(
    1. List<String>,
    2. int
    )
)

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;
}