Skip to content
heff

std.csv

CSV (RFC 4180), read and written as Go’s encoding/csv reads and writes it with its settings left as they are: a record a line, ended by a line feed or a carriage return and a line feed, its fields between commas. A field may be quoted with ", a "" in it one "; quoted, it may hold commas and line breaks (one written as a carriage return and a line feed read as a line feed, as Go reads it). Reading skips an empty line, and every record must have as many fields as the first. Import it by a name, import std.csv as CSV.

import std.csv as CSV
-- | >>> names
-- | Right ["Ada", "Grace"]
names : Either CSV.ParseError (List String)
names = case CSV.parse "name,born\nAda,1815\nGrace,1906\n" of
Right (_ :: rows) -> Right (List.concatMap (List.take 1) rows)
Right Nil -> Right Nil
Left e -> Left e

ParseError

type ParseError = { line : Int, column : Int, message : String }

Where the text is not CSV: its line and its column there (from 1, the column counted in bytes), and what is wrong, in Go’s words.

parse

parse : String -> Either ParseError (List (List String))

The records of a text, each a list of its fields. A line break at the end makes no record, nor does an empty text, nor an empty line.

>>> parse "a,b,c\n1,2,3\n"
Right [["a", "b", "c"], ["1", "2", "3"]]
>>> parse "x,,\r\n\r\n,y,\"\"\r\nlast,one,here"
Right [["x", "", ""], ["", "y", ""], ["last", "one", "here"]]
>>> parse ""
Right []

(a quoted field: its commas, line breaks and doubled quotes; a carriage return and a line feed in it read as a line feed)

>>> parse "\"a, b\",\"say \"\"hi\"\"\"\n\"two\nlines\",\"cr\r\nlf\"\n"
Right [["a, b", "say \"hi\""], ["two\nlines", "cr\nlf"]]

(where it is not CSV: a quote in a field not quoted, text after a closing quote, a quote not closed, a record of another width)

>>> parse "a,b\nc,d\"e\n"
Left { line = 2, column = 4, message = "bare \" in non-quoted-field" }
>>> parse "\"a\"b,c"
Left { line = 1, column = 4, message = "extraneous or missing \" in quoted-field" }
>>> parse "a\n\"b\nc"
Left { line = 3, column = 2, message = "extraneous or missing \" in quoted-field" }
>>> parse "a,b\nc\n"
Left { line = 2, column = 1, message = "wrong number of fields" }

render

render : List (List String) -> String

The text of records, as Go’s csv.Writer writes it: each record ended by a line feed, its fields between commas; a field quoted where it has a comma, a quote or a line break in it, or starts with a space, each " in it doubled.

>>> render [["a", "b c", "d,e"], ["say \"hi\"", " x", "two\nlines"]]
"a,b c,\"d,e\"\n\"say \"\"hi\"\"\",\" x\",\"two\nlines\"\n"
>>> render []
""

(what it writes, parse reads back)

>>> parse (render [["", "\"", "a,b"], [" x", "", "two\nlines"]])
Right [["", "\"", "a,b"], [" x", "", "two\nlines"]]