【Haskell】CSVパーサ(WEB+DB PRESS vol.67 2012より)

import Control.Applicative ((<*), (*>))
import Text.Parsec
import Text.Parsec.String

csv :: Parser [[String]]
csv = endBy1 record crlf

record :: Parser [String]
record = sepBy1 field comma

field :: Parser String
field = escaped <|> nonEscaped

escaped :: Parser String
escaped = dquote *> many (textdata <|> comma <|> cr <|> lf <|> try (dquote *> dquote)) <* dquote

nonEscaped :: Parser String
nonEscaped = many textdata

textdata :: Parser Char
textdata = oneOf (" !" ++ ['#' .. '+'] ++ ['-' .. '~'])

comma :: Parser Char
comma = char ','

crlf :: Parser Char
crlf = cr *> lf

lf :: Parser Char
lf = char '\x0a'

cr :: Parser Char
cr = char '\x0d'

dquote :: Parser Char
dquote = char '"'