{- | 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 -}