Skip to content

Commit 5be183c

Browse files
committed
Make the CSV parser customizable.
1 parent 42bf752 commit 5be183c

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

bin/benchmark/suites/example_benchmark.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const bibtexInput = '@inproceedings{Reng10c,\n'
1919
'\tYear = 2010,\n'
2020
'\tUrl = {http://scg.unibe.ch/archive/papers/Reng10cDynamicGrammars.pdf}}';
2121

22-
final csvParser = csv_example.csv;
22+
final csvParser = csv_example.CsvDefinition().build();
2323
const csvInput = 'Los Angeles,34°03′N,118°15′W\n'
2424
'New York City,40°42′46″N,74°00′21″W\n'
2525
'Paris,48°51′24″N,2°21′03″E';

lib/csv.dart

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,46 @@ library;
33

44
import 'package:petitparser/petitparser.dart';
55

6-
final csv = _lines.end();
6+
class CsvDefinition extends GrammarDefinition<List<List<String>>> {
7+
CsvDefinition({
8+
this.quoteChar = '"',
9+
this.escapeChar = '"',
10+
this.delimiter = ",",
11+
this.newline = "\n",
12+
});
713

8-
final _lines = _records.starSeparated(newline()).map((list) => list.elements);
9-
final _records = _field.starSeparated(char(',')).map((list) => list.elements);
14+
final String quoteChar;
15+
final String escapeChar;
16+
final String delimiter;
17+
final String newline;
1018

11-
final _field = _quotedField | _plainField;
19+
@override
20+
Parser<List<List<String>>> start() => ref0(lines).end();
1221

13-
final _quotedField =
14-
_quotedFieldContent.skip(before: char('"'), after: char('"'));
15-
final _quotedFieldContent = _quotedFieldChar.star().map((list) => list.join());
16-
final _quotedFieldChar = string('""').map((value) => value[0]) | pattern('^"');
22+
Parser<List<List<String>>> lines() =>
23+
ref0(records).starSeparated(string(newline)).map((list) => list.elements);
24+
Parser<List<String>> records() =>
25+
ref0(field).starSeparated(char(delimiter)).map((list) => list.elements);
1726

18-
final _plainField = _plainFieldContent;
19-
final _plainFieldContent = _plainFieldChar.starString();
20-
final _plainFieldChar = pattern("^,\n\r");
27+
Parser<String> field() => [
28+
ref0(quotedField),
29+
ref0(plainField),
30+
].toChoiceParser();
31+
32+
Parser<String> quotedField() => ref0(quotedFieldContent)
33+
.skip(before: char(quoteChar), after: char(quoteChar));
34+
Parser<String> quotedFieldContent() =>
35+
ref0(quotedFieldChar).star().map((list) => list.join());
36+
Parser<String> quotedFieldChar() => [
37+
seq2(char(escapeChar), any()).map2((_, char) => char),
38+
pattern('^$quoteChar'),
39+
].toChoiceParser();
40+
41+
Parser<String> plainField() => ref0(plainFieldContent);
42+
Parser<String> plainFieldContent() =>
43+
ref0(plainFieldChar).star().map((list) => list.join());
44+
Parser<String> plainFieldChar() => [
45+
seq2(char(escapeChar), any()).map2((_, char) => char),
46+
pattern("^$delimiter$newline")
47+
].toChoiceParser();
48+
}

test/csv_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:test/test.dart';
55
import 'utils/expect.dart';
66

77
void main() {
8+
final csv = CsvDefinition().build();
89
test('linter', () {
910
expect(linter(csv, excludedTypes: {}), isEmpty);
1011
});

0 commit comments

Comments
 (0)