module Text.Comma
( comma
, uncomma
) where
import Control.Applicative
import Data.List
import qualified Data.Attoparsec.Text as A
import qualified Data.Text as T
field :: A.Parser T.Text
field = fmap T.concat quoted <|> normal A.<?> "field"
where
normal = A.takeWhile (A.notInClass "\n\r,\"") A.<?> "normal field"
quoted = A.char '"' *> many between <* A.char '"' A.<?> "quoted field"
between = A.takeWhile1 (/= '"') <|> (A.string "\"\"" *> pure "\"")
comma :: T.Text
-> Either String [[T.Text]]
comma text = A.parseOnly table (T.stripEnd text)
where
table = A.sepBy1 record A.endOfLine A.<?> "table"
record = A.sepBy1 field (A.char ',') A.<?> "record"
uncomma :: [[T.Text]]
-> T.Text
uncomma = T.unlines . map (\r -> T.concat $ intersperse "," (map conv r))
where
isQuoted = T.any (`elem` ['"', '\n', '\r'])
enquote x = T.concat ["\"", x, "\""]
conv f
| isQuoted f = enquote (T.replace "\"" "\"\"" f)
| otherwise = f