module Data.CSV.Conduit.Parser.Text
( parseCSV
, parseRow
, row
, csv
) where
import Control.Applicative
import Control.Monad (mzero, mplus, foldM, when, liftM)
import Control.Monad.IO.Class (liftIO, MonadIO)
import Data.Attoparsec.Text as P hiding (take)
import qualified Data.Attoparsec.Text as T
import qualified Data.Map as M
import Data.Text (Text)
import qualified Data.Text as T
import Data.Word (Word8)
import Data.CSV.Conduit.Types
parseCSV :: CSVSettings -> Text -> Either String [Row Text]
parseCSV s = parseOnly $ csv s
parseRow :: CSVSettings -> Text -> Either String (Maybe (Row Text))
parseRow s = parseOnly $ row s
csv :: CSVSettings -> Parser [Row Text]
csv s = do
r <- row s
end <- atEnd
case end of
True -> case r of
Just x -> return [x]
Nothing -> return []
False -> do
rest <- csv s
return $ case r of
Just x -> x : rest
Nothing -> rest
row :: CSVSettings -> Parser (Maybe (Row Text))
row csvs = csvrow csvs <|> badrow
badrow :: Parser (Maybe (Row Text))
badrow = P.takeWhile (not . T.isEndOfLine) *>
(T.endOfLine <|> T.endOfInput) *> return Nothing
csvrow :: CSVSettings -> Parser (Maybe (Row Text))
csvrow c =
let rowbody = (quotedField' <|> (field c)) `sepBy` T.char (csvSep c)
properrow = rowbody <* (T.endOfLine <|> P.endOfInput)
quotedField' = case csvQuoteChar c of
Nothing -> mzero
Just q' -> try (quotedField q')
in do
res <- properrow
return $ Just res
field :: CSVSettings -> Parser Text
field s = P.takeWhile (isFieldChar s)
isFieldChar s = notInClass xs'
where xs = csvSep s : "\n\r"
xs' = case csvQuoteChar s of
Nothing -> xs
Just x -> x : xs
quotedField :: Char -> Parser Text
quotedField c =
let quoted = string dbl *> return c
dbl = T.pack [c,c]
in do
T.char c
f <- many (T.notChar c <|> quoted)
T.char c
return $ T.pack f