librarylibs/Csv/src/Csv.xtl
Csv: comma-separated values -- lines to fields (quoted fields kept whole), a table of texts, columns by number or name, numbers, and back to text. Import it with an alias of your choice: "cs:" u_se< "Csv". Put libs/Csv/src on XETAL_PATH ("just path"); the reference is libs/Csv/docs. Names with l: are exported; those under h: are private to this file.
A table is a matrix of texts (Box Char), a row per line, its first row the header. Fields follow RFC 4180: a field in double quotes may hold commas, and a doubled quote inside stands for one.
Parsing
ʰu̲nquote : Char -> Char
A field as written to its value: outer quotes off, "" to ".
ʰu̲nquote ← { f → 2 > t̲ally f ? f n̲ot (dq m̲atch 1 t̲ake f) ∧ dq m̲atch -1 t̲ake f ? f ((e̲nclose dq c̲at dq) c̲at e̲nclose dq) ᵗr̲eplace 1 d̲rop -1 d̲rop f }
ˡf̲ields : Char -> Box Char
f_ields line: the fields of one line. A comma separates fields unless an odd number of quotes comes before it (it is inside a quoted field).
ˡf̲ields ← { line → inside ← 1 = ('+ s̲\ 0 + line = f̲irst dq) m̲od 2 cut ← w̲here (line = f̲irst ",") ∧ n̲ot inside starts ← 1 c̲at cut + 1 ends ← cut c̲at 1 + t̲ally line '{ i → ʰu̲nquote ((f̲irst i s̲elect ends) − f̲irst i s̲elect starts) t̲ake ((f̲irst i s̲elect starts) − 1) d̲rop line } m̲ap r̲ange t̲ally starts }
ˡr̲ows : Char -> Box Char
r_ows text: the table of a whole text, a row per line (every line has the same number of fields).
ˡr̲ows ← { text → lines ← ᵗl̲ines text rows ← '{ l → ˡf̲ields d̲isclose l } m̲ap lines ((t̲ally lines) c̲at t̲ally d̲isclose f̲irst rows) r̲eshape q:r̲aze rows }
Columns
ˡc̲olumn : Int -> a -> a
n c_olumn table: the texts of column n, the header left out.
ˡc̲olumn ← { n table → 1 d̲rop n s̲elect₂ table }
ˡf̲ield : Eq a => a -> Box a -> Box a
name f_ield table: the texts of the column whose header is name.
ˡf̲ield ← { name table → (f̲irst (f̲irst table) i̲ndexOf e̲nclose name) ˡc̲olumn table }
ˡn̲umbers : Char -> Box Char -> Float
name n_umbers table: the column whose header is name, as numbers.
ˡn̲umbers ← { name table → n̲umbers " " ᵗj̲oin name ˡf̲ield table }