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,\"") 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 fixEnd
where
table = A.sepBy1 record (A.char '\n') A.<?> "table"
record = A.sepBy1 field (A.char ',') A.<?> "record"
fixEnd = maybe text id (T.stripSuffix "\n" text)
uncomma :: [[T.Text]]
-> T.Text
uncomma = T.unlines . map (T.concat . intersperse "," . map conv)
where
isQuoted = T.any (`elem` ['"', '\n', ','])
enquote x = T.concat ["\"", x, "\""]
conv f
| isQuoted f = enquote (T.replace "\"" "\"\"" f)
| otherwise = f