{-# LANGUAGE Safe #-}
module Data.CSV (csvFile, genCsvFile) where
import safe Text.ParserCombinators.Parsec
( char,
noneOf,
string,
endBy,
sepBy,
(<?>),
(<|>),
many,
try,
GenParser,
CharParser )
import Data.List (intersperse)
eol :: forall st. GenParser Char st String
eol :: forall st. GenParser Char st String
eol = (GenParser Char st String -> GenParser Char st String
forall tok st a. GenParser tok st a -> GenParser tok st a
try (GenParser Char st String -> GenParser Char st String)
-> GenParser Char st String -> GenParser Char st String
forall a b. (a -> b) -> a -> b
$ String -> GenParser Char st String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\n\r") GenParser Char st String
-> GenParser Char st String -> GenParser Char st String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (GenParser Char st String -> GenParser Char st String
forall tok st a. GenParser tok st a -> GenParser tok st a
try (GenParser Char st String -> GenParser Char st String)
-> GenParser Char st String -> GenParser Char st String
forall a b. (a -> b) -> a -> b
$ String -> GenParser Char st String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\r\n") GenParser Char st String
-> GenParser Char st String -> GenParser Char st String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> GenParser Char st String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\n" GenParser Char st String
-> GenParser Char st String -> GenParser Char st String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
String -> GenParser Char st String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\r" GenParser Char st String -> String -> GenParser Char st String
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"End of line"
cell :: GenParser Char st String
cell :: forall st. GenParser Char st String
cell = CharParser st String
forall st. GenParser Char st String
quotedcell CharParser st String
-> CharParser st String -> CharParser st String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String st Identity Char -> CharParser st String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (String -> ParsecT String st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
",\n\r")
quotedchar :: GenParser Char st Char
quotedchar :: forall st. GenParser Char st Char
quotedchar = String -> ParsecT String st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\""
ParsecT String st Identity Char
-> ParsecT String st Identity Char
-> ParsecT String st Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (ParsecT String st Identity Char -> ParsecT String st Identity Char
forall tok st a. GenParser tok st a -> GenParser tok st a
try (ParsecT String st Identity Char
-> ParsecT String st Identity Char)
-> ParsecT String st Identity Char
-> ParsecT String st Identity Char
forall a b. (a -> b) -> a -> b
$ do String
_ <- String -> ParsecT String st Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\"\""
Char -> ParsecT String st Identity Char
forall (m :: * -> *) a. Monad m => a -> m a
return Char
'"'
)
quotedcell :: CharParser st String
quotedcell :: forall st. GenParser Char st String
quotedcell = do Char
_ <- Char -> ParsecT String st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"'
String
content <- ParsecT String st Identity Char -> CharParser st String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT String st Identity Char
forall st. GenParser Char st Char
quotedchar
Char
_ <- Char -> ParsecT String st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"'
String -> CharParser st String
forall (m :: * -> *) a. Monad m => a -> m a
return String
content
line :: GenParser Char st [String]
line :: forall st. GenParser Char st [String]
line = ParsecT String st Identity String
-> ParsecT String st Identity Char
-> ParsecT String st Identity [String]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
sepBy ParsecT String st Identity String
forall st. GenParser Char st String
cell (Char -> ParsecT String st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
',')
csvFile :: CharParser st [[String]]
csvFile :: forall st. CharParser st [[String]]
csvFile = ParsecT String st Identity [String]
-> ParsecT String st Identity String
-> ParsecT String st Identity [[String]]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
endBy ParsecT String st Identity [String]
forall st. GenParser Char st [String]
line ParsecT String st Identity String
forall st. GenParser Char st String
eol
genCsvFile :: [[String]] -> String
genCsvFile :: [[String]] -> String
genCsvFile [[String]]
inp =
[String] -> String
unlines ([String] -> String)
-> ([[String]] -> [String]) -> [[String]] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> String
csvline ([[String]] -> String) -> [[String]] -> String
forall a b. (a -> b) -> a -> b
$ [[String]]
inp
where csvline :: [String] -> String
csvline :: [String] -> String
csvline [String]
l = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
"," ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
csvcells ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [String]
l
csvcells :: String -> String
csvcells :: String -> String
csvcells String
"" = String
""
csvcells String
c = Char
'"' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
convcell String
c String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
convcell :: String -> String
convcell :: String -> String
convcell String
c = (Char -> String) -> String -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Char -> String
convchar String
c
convchar :: Char -> String
convchar Char
'"' = String
"\"\""
convchar Char
x = [Char
x]