diff options
Diffstat (limited to 'src/CSV.hs')
-rw-r--r-- | src/CSV.hs | 71 |
1 files changed, 50 insertions, 21 deletions
@@ -2,6 +2,7 @@ module CSV( Settings(..), + specialChars, defaultSettings, parseRecord @@ -10,50 +11,78 @@ module CSV( -import Text.ParserCombinators.Parsec -import Data.Char +import Text.ParserCombinators.Parsec ( (<|>), (<?>) ) +import qualified Text.ParserCombinators.Parsec as Parsec +import qualified Data.Char as Char -data Settings = Settings { separator :: Char - , quote :: Char - , escape :: Char } +data Settings = Settings + { separator :: Char + , quote :: Char + , escape :: Char } -specialChars :: Settings -> String -specialChars s = (separator s):(quote s):(escape s):[] -defaultSettings = Settings { separator = ',', quote = '\"', escape = '\\' } +defaultSettings = Settings + { separator = ',' + , quote = '\"' + , escape = '\\' } -parseRecord :: Settings -> String -> Either ParseError [String] -parseRecord settings input = - parse (record settings) "error" input +specialChars :: Settings -> String +specialChars s = (separator s):(quote s):(escape s):[] + +parseRecord :: Settings -> String -> Either Parsec.ParseError [String] +parseRecord settings input = + Parsec.parse (record settings) "error" input + record s = do - f <- (field s) `sepBy` (char (separator s)) - optional eol - eof + f <- (field s) `Parsec.sepBy` (Parsec.char (separator s)) + Parsec.optional eol + Parsec.eof return f -field s = many (try (quoted s) <|> many1 (fieldChar s)) >>= return . foldl1 (++) -quoted s = between (char (quote s)) (char (quote s)) (many (quotedChar s)) +field s = + Parsec.many (Parsec.try (quoted s) <|> Parsec.many1 (fieldChar s)) >>= + return . foldl1 (++) + + +quoted s = + Parsec.between + (Parsec.char (quote s)) + (Parsec.char (quote s)) + (Parsec.many (quotedChar s)) + + fieldChar s = allExcept s (specialChars s) + + quotedChar s = allExcept s [quote s] -allExcept s c = try (escapeChar s) <|> satisfy (\x -> (not (isControl x)) && (x `notElem` c)) -escapeChar s = char (escape s) >> oneOf (specialChars s) -eol = try (string "\r\n") - <|> try (string "\r") - <|> try (string "\n") +allExcept s c = + Parsec.try (escapeChar s) <|> + Parsec.satisfy (\x -> (not (Char.isControl x)) && (x `notElem` c)) + + +escapeChar s = do + Parsec.char (escape s) + Parsec.oneOf (specialChars s) + + +eol = Parsec.try (Parsec.string "\r\n") + <|> Parsec.try (Parsec.string "\r") + <|> Parsec.try (Parsec.string "\n") <?> "end of line" + |