Emping-0.5: src/CSVParse.hs
{- | Emping 0.4, 0.5 (provisional)
Module CSVParse converts a table in Open Office Calc .csv format into a list of lists of Haskell Strings.The first row in the table must consist of the attribute names. It is recommended that all attributes have unique names, but blanks and doubles are allowed. Each attribute will be identified by its column number.
The rows after the first must be attribute values. Values in different columns may have the same names or be blank. Values in the same column with the same names are considered to be equal. Emping will generate a list of values for each column.
Warning: if you use blank fields in the table, be sure they are correctly seperated by comma's and that each row is correctly terminated by a newline.
Fri 04 Apr 2008 07:17:12 PM CEST
-}
module CSVParse ( getTable , blankId ) where
import Text.ParserCombinators.Parsec
{- |
a text field starts with \" and ends with \"
a numerical field consists of digits only
an empty field is zero or more spaces separated by comma's, returns \"NA\"
-}
comma:: GenParser Char a Char
comma = char ','
-- | textField returns any String between double quotes (the OO Calc format)
txtField :: GenParser Char a String
txtField = do char '\"'
txt <- many (noneOf "\"")
char '\"'; return txt
-- | numField returns a string of digits as a string. This is the OO Calc format for numbers.
numField :: GenParser Char a String
numField = many1 digit
-- | blankId is the String returned from parsing a blank field. Currently this is: \"NA\", which stands for 'not applicable'.
blankId :: String
blankId = "NA"
-- | noField parses a blank field
noField :: GenParser Char a String
noField = do { many (char ' '); return blankId }
-- | getField parses a text field, a numeric field, or a blank field
getField :: GenParser Char a String
getField = do {txtField <|> numField <|> noField }
-- | csvLine parses a row
csvLine :: GenParser Char a [String]
csvLine = do fields <- (sepBy getField comma)
newline
return fields
-- | csvTable parses the table
csvTable :: GenParser Char a [[String]]
csvTable = many csvLine
-- | getTable reads the table from a file path and returns a list of row representations, each itself a list of strings
getTable :: String -> IO [[String]]
getTable fname = do pares <- parseFromFile csvTable fname
let res = case pares of
Right x -> x
Left err -> error (show err)
return (res)
{-
-- test the table in csv format for parse errors
test = do putStrLn "Enter CSV file:"
name <- getLine
res <- parseFromFile csvTable name
case res of Left err -> print err
Right xs -> print xs
-}