betto_codec_csv 0.1.0-dev.1
betto_codec_csv: ^0.1.0-dev.1 copied to clipboard
A configurable CSV parser for Dart with RFC 4180 support. Decodes delimiter-separated text into a RecordSet.
betto_codec_csv #
A configurable CSV codec for Dart. Decodes delimiter-separated text into a
RecordSet, and encodes a RecordSet back into
delimiter-separated text.
It's built around a CsvDialect rather than a fixed comma-and-quote format, so
the same codec handles RFC 4180 CSV, TSV, Markdown-style pipe tables, and files
with comments or boilerplate header lines to skip.
Features #
- RFC 4180 support — quoted fields, escaped quotes (
""), and multi-line values, viaRfc4180Dialect/CsvDialect.rfc4180. - Custom dialects — configurable delimiter, quote character, "bookend"
character (e.g.
|for pipe tables), and whitespace trimming. - Header rows — infer field names from the first row, or supply a
RecordSetHeaderup front to assign field names and types as rows are parsed. - Comments — ignore full comment lines or trailing inline comments.
- Line skipping — ignore specific line numbers (e.g. banner/metadata rows), including negative indices counted from the end of the file.
- Round-trip encoding — render a
RecordSetback to text with the sameCsvDialectused to parse it. - Clear errors — parse failures raise
CsvExceptionwith the line and column at which they occurred.
Getting started #
Add the package to your pubspec.yaml (path dependency within this monorepo):
dependencies:
betto_codec_csv: 0.1.0-dev.1
Usage #
Basic decoding #
import 'package:betto_codec_csv/betto_codec_csv.dart';
void main() {
final result = Decoder().decode('a,b,c\nd,e,f');
print(result.recordAt(0).values); // [a, b, c]
print(result.recordAt(1).values); // [d, e, f]
}
There's also a top-level shorthand:
final result = csvDecode('a,b,c\nd,e,f');
Basic encoding #
final source = Encoder().encode(result);
Or the top-level shorthand:
final source = csvEncode(result);
Header rows #
Let the first row supply field names:
final csv = Decoder(dialect: CsvDialect(hasHeaderRow: true));
final result = csv.decode('first,second,third\n1,2,3');
print(result.header!.fieldNames); // [first, second, third]
print(result.first['first']!.value); // 1
Or supply a typed header up front and skip inferring it from the data:
final header = RecordSetHeader(
schema: [
FieldSchema.string('name'),
FieldSchema.int('age'),
FieldSchema.bool('active'),
],
);
final csv = Decoder(dialect: CsvDialect(), header: header);
final result = csv.decode('storm,28,true\nkyle,32,false');
RFC 4180 (quoted values, embedded newlines) #
final csv = Decoder(dialect: Rfc4180Dialect());
final result = csv.decode('"a","b\nmulti-line","c"');
CsvCodec bundles an RFC 4180 Decoder/Encoder pair as a single
Codec<RecordSet, String>, and the shared csv constant is a ready-to-use
instance:
final result = csv.decoder.convert('"a","b\nmulti-line","c"');
final source = csv.encoder.convert(result);
Pipe tables #
final csv = Decoder(dialect: CsvDialect(delimiter: '|', bookendChar: '|'));
final result = csv.decode('|a|b|c|');
Comments and ignored lines #
final dialect = CsvDialect(
lineCommentMarker: '#', // lines starting with # are skipped
ignoredLines: {1}, // also skip line 1 (e.g. a title row)
);
final csv = Decoder(dialect: dialect);
See CsvDialect for the full set of options (trimSurroundingWhitespace,
ignoreEmptyLines, multiLineRecords, inlineCommentMarker, etc.), and the
test/ directory for further worked examples of each.