module Data.CSV.Conduit.Parser.ByteString
( parseCSV
, parseRow
, row
, csv
) where
import Control.Applicative
import Control.Monad (mzero)
import Data.Attoparsec.ByteString as P hiding (take)
import qualified Data.Attoparsec.ByteString.Char8 as C8
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B8
import Data.Word (Word8)
import Data.CSV.Conduit.Types
parseCSV :: CSVSettings -> ByteString -> Either String [Row ByteString]
parseCSV :: CSVSettings -> ByteString -> Either String [Row ByteString]
parseCSV CSVSettings
s = Parser [Row ByteString]
-> ByteString -> Either String [Row ByteString]
forall a. Parser a -> ByteString -> Either String a
parseOnly (Parser [Row ByteString]
-> ByteString -> Either String [Row ByteString])
-> Parser [Row ByteString]
-> ByteString
-> Either String [Row ByteString]
forall a b. (a -> b) -> a -> b
$ CSVSettings -> Parser [Row ByteString]
csv CSVSettings
s
parseRow :: CSVSettings -> ByteString -> Either String (Maybe (Row ByteString))
parseRow :: CSVSettings -> ByteString -> Either String (Maybe (Row ByteString))
parseRow CSVSettings
s = Parser (Maybe (Row ByteString))
-> ByteString -> Either String (Maybe (Row ByteString))
forall a. Parser a -> ByteString -> Either String a
parseOnly (Parser (Maybe (Row ByteString))
-> ByteString -> Either String (Maybe (Row ByteString)))
-> Parser (Maybe (Row ByteString))
-> ByteString
-> Either String (Maybe (Row ByteString))
forall a b. (a -> b) -> a -> b
$ CSVSettings -> Parser (Maybe (Row ByteString))
row CSVSettings
s
csv :: CSVSettings -> Parser [Row ByteString]
csv :: CSVSettings -> Parser [Row ByteString]
csv CSVSettings
s = do
Maybe (Row ByteString)
r <- CSVSettings -> Parser (Maybe (Row ByteString))
row CSVSettings
s
Bool
end <- Parser ByteString Bool
forall t. Chunk t => Parser t Bool
atEnd
if Bool
end
then case Maybe (Row ByteString)
r of
Just Row ByteString
x -> [Row ByteString] -> Parser [Row ByteString]
forall (m :: * -> *) a. Monad m => a -> m a
return [Row ByteString
x]
Maybe (Row ByteString)
Nothing -> [Row ByteString] -> Parser [Row ByteString]
forall (m :: * -> *) a. Monad m => a -> m a
return []
else do
[Row ByteString]
rest <- CSVSettings -> Parser [Row ByteString]
csv CSVSettings
s
[Row ByteString] -> Parser [Row ByteString]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Row ByteString] -> Parser [Row ByteString])
-> [Row ByteString] -> Parser [Row ByteString]
forall a b. (a -> b) -> a -> b
$ case Maybe (Row ByteString)
r of
Just Row ByteString
x -> Row ByteString
x Row ByteString -> [Row ByteString] -> [Row ByteString]
forall a. a -> [a] -> [a]
: [Row ByteString]
rest
Maybe (Row ByteString)
Nothing -> [Row ByteString]
rest
row :: CSVSettings -> Parser (Maybe (Row ByteString))
row :: CSVSettings -> Parser (Maybe (Row ByteString))
row CSVSettings
csvs = CSVSettings -> Parser (Maybe (Row ByteString))
csvrow CSVSettings
csvs Parser (Maybe (Row ByteString))
-> Parser (Maybe (Row ByteString))
-> Parser (Maybe (Row ByteString))
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (Maybe (Row ByteString))
badrow
badrow :: Parser (Maybe (Row ByteString))
badrow :: Parser (Maybe (Row ByteString))
badrow = (Word8 -> Bool) -> Parser ByteString
P.takeWhile (Bool -> Bool
not (Bool -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Bool
C8.isEndOfLine) Parser ByteString -> Parser ByteString () -> Parser ByteString ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
(Parser ByteString ()
C8.endOfLine Parser ByteString ()
-> Parser ByteString () -> Parser ByteString ()
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ByteString ()
forall t. Chunk t => Parser t ()
C8.endOfInput) Parser ByteString ()
-> Parser (Maybe (Row ByteString))
-> Parser (Maybe (Row ByteString))
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Maybe (Row ByteString) -> Parser (Maybe (Row ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Row ByteString)
forall a. Maybe a
Nothing
csvrow :: CSVSettings -> Parser (Maybe (Row ByteString))
csvrow :: CSVSettings -> Parser (Maybe (Row ByteString))
csvrow CSVSettings
c =
let rowbody :: Parser ByteString (Row ByteString)
rowbody = (Parser ByteString
quotedField' Parser ByteString -> Parser ByteString -> Parser ByteString
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> CSVSettings -> Parser ByteString
field CSVSettings
c) Parser ByteString
-> Parser ByteString Char -> Parser ByteString (Row ByteString)
forall (f :: * -> *) a s. Alternative f => f a -> f s -> f [a]
`sepBy` Char -> Parser ByteString Char
C8.char (CSVSettings -> Char
csvSep CSVSettings
c)
properrow :: Parser ByteString (Row ByteString)
properrow = Parser ByteString (Row ByteString)
rowbody Parser ByteString (Row ByteString)
-> Parser ByteString () -> Parser ByteString (Row ByteString)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* (Parser ByteString ()
C8.endOfLine Parser ByteString ()
-> Parser ByteString () -> Parser ByteString ()
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ByteString ()
forall t. Chunk t => Parser t ()
P.endOfInput)
quotedField' :: Parser ByteString
quotedField' = case CSVSettings -> Maybe Char
csvQuoteChar CSVSettings
c of
Maybe Char
Nothing -> Parser ByteString
forall (m :: * -> *) a. MonadPlus m => m a
mzero
Just Char
q' -> Parser ByteString -> Parser ByteString
forall i a. Parser i a -> Parser i a
try (Char -> Parser ByteString
quotedField Char
q')
in do
Row ByteString
res <- Parser ByteString (Row ByteString)
properrow
Maybe (Row ByteString) -> Parser (Maybe (Row ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Row ByteString) -> Parser (Maybe (Row ByteString)))
-> Maybe (Row ByteString) -> Parser (Maybe (Row ByteString))
forall a b. (a -> b) -> a -> b
$ Row ByteString -> Maybe (Row ByteString)
forall a. a -> Maybe a
Just Row ByteString
res
field :: CSVSettings -> Parser ByteString
field :: CSVSettings -> Parser ByteString
field CSVSettings
s = (Word8 -> Bool) -> Parser ByteString
P.takeWhile (CSVSettings -> Word8 -> Bool
isFieldChar CSVSettings
s)
isFieldChar :: CSVSettings -> Word8 -> Bool
isFieldChar :: CSVSettings -> Word8 -> Bool
isFieldChar CSVSettings
s = String -> Word8 -> Bool
notInClass String
xs'
where xs :: String
xs = CSVSettings -> Char
csvSep CSVSettings
s Char -> String -> String
forall a. a -> [a] -> [a]
: String
"\n\r"
xs' :: String
xs' = case CSVSettings -> Maybe Char
csvQuoteChar CSVSettings
s of
Maybe Char
Nothing -> String
xs
Just Char
x -> Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs
quotedField :: Char -> Parser ByteString
quotedField :: Char -> Parser ByteString
quotedField Char
c =
let quoted :: Parser ByteString Char
quoted = ByteString -> Parser ByteString
string ByteString
dbl Parser ByteString
-> Parser ByteString Char -> Parser ByteString Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Char -> Parser ByteString Char
forall (m :: * -> *) a. Monad m => a -> m a
return Char
c
dbl :: ByteString
dbl = String -> ByteString
B8.pack [Char
c,Char
c]
in do
Char
_ <- Char -> Parser ByteString Char
C8.char Char
c
String
f <- Parser ByteString Char -> Parser ByteString String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Char -> Parser ByteString Char
C8.notChar Char
c Parser ByteString Char
-> Parser ByteString Char -> Parser ByteString Char
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ByteString Char
quoted)
Char
_ <- Char -> Parser ByteString Char
C8.char Char
c
ByteString -> Parser ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Parser ByteString)
-> ByteString -> Parser ByteString
forall a b. (a -> b) -> a -> b
$ String -> ByteString
B8.pack String
f