circuits-parser
Safe HaskellNone
LanguageGHC2024

Circuit.Parser.Csv

Description

CSV for the circuits ecosystem: RFC 4180 on Circuit.Parser combinators.

Where Circuit.Parser.Json skips whitespace, csv skips nothing — spaces are data, line endings are structure. The dialect:

  • line endings lenient: \r\n | \n | \r.
  • quoting strict: " opens a quoted field only at field start; inside a quoted field "" is an escaped quote; after the closing quote only ,, EOL, or EOF may follow. A bare " inside a plain field is rejected.
  • a trailing comma is a field: a,b, is three fields. An empty line is one record of one empty field. The final record may omit its line ending. Empty input is zero records.
  • field-count consistency across records is not checked — consumer policy, like duplicate keys in json.
Synopsis

The table

newtype Csv Source #

A CSV table: rows of fields, source order. No header policy — headers are a consumer convention, not a parsing fact.

Constructors

Csv (Vector (Vector Text)) 

Instances

Instances details
Eq Csv Source # 
Instance details

Defined in Circuit.Parser.Csv

Methods

(==) :: Csv -> Csv -> Bool #

(/=) :: Csv -> Csv -> Bool #

Show Csv Source # 
Instance details

Defined in Circuit.Parser.Csv

Methods

showsPrec :: Int -> Csv -> ShowS #

show :: Csv -> String #

showList :: [Csv] -> ShowS #

Parsing

csv :: Parser Identity ByteString Char Csv Source #

Parse a whole CSV table.

record :: Parser Identity ByteString Char [Text] Source #

Parse one record: fields separated by commas. A trailing comma is a trailing empty field.

field :: Parser Identity ByteString Char Text Source #

Parse one field, quoted or plain. try is load-bearing: without it, a failed quoted attempt (say, an unterminated quote) would hand the plain alternative the stream at the point of failure — consumed quote and all — and an unterminated quote would silently parse as an empty field.

Boundary

decodeCsv :: ByteString -> Either String Csv Source #

Parse a CSV document, rejecting trailing garbage.

>>> decodeCsv (C.pack "a,b\r\nc,d\r\n")
Right (Csv [["a","b"],["c","d"]])
>>> decodeCsv (C.pack "name,note\n\"say \"\"hi\"\"\",ok")
Right (Csv [["name","note"],["say \"hi\"","ok"]])
>>> decodeCsv (C.pack "a,b,\n")
Right (Csv [["a","b",""]])
>>> decodeCsv (C.pack "")
Right (Csv [])
>>> decodeCsv (C.pack "a\"b,c")
Left "invalid CSV"