packages feed

Emping-0.6: src/CsvParse.hs

{- | Emping 0.6 (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.

Tue 19 May 2009 05:50:37 PM CEST 
-}
module CsvParse ( getTable , blankId  ) where

import Text.ParserCombinators.Parsec

{- |
a text field starts with \" and ends with \" any other character is allowed
a numerical field consists of digits only 
an empty field is zero or more spaces separated by comma's, returns \"NA\" 
-}

-- | blankId is the String returned from parsing a blank field 
--   currently this is: \"NA\", which stands for 'not applicable' 
blankId :: String
blankId = "NA"

comma:: Parser Char
comma = char ','

-- textField returns any String between double quotes (the OO Calc format)
txtField :: Parser 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 :: Parser String              
numField = many1 digit 

-- noField parses a blank field
noField :: Parser String
noField = do { many (char ' '); return blankId }

-- getField parses a text field, a numeric field, or a blank field
getField :: Parser String
getField = do {txtField <|> numField <|> noField } 

-- csvLine parses a row
csvLine :: Parser [String]
csvLine = do  fields <- (sepBy getField comma)
              newline 
              return fields

--  csvTable parses the table
csvTable :: Parser [[String]]
csvTable = many csvLine

-- | getTable reads the table from a file path 
-- it returns a list of rows, where each row is 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 ("parse error at: " ++ (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 -> error ("parse error at: " ++ (show err))
                      Right xs -> print xs
-}