lazy-csv 0.4 → 0.5
raw patch · 5 files changed
+65/−17 lines, 5 files
Files
- Text/CSV/Lazy/ByteString.hs +24/−7
- Text/CSV/Lazy/String.hs +29/−7
- changelog.html +6/−0
- index.html +5/−2
- lazy-csv.cabal +1/−1
Text/CSV/Lazy/ByteString.hs view
@@ -50,7 +50,7 @@ -- , ppCSVTableAsTuples import Data.List (groupBy, partition, elemIndex, intercalate, takeWhile- ,(\\), nub)+ ,deleteFirstsBy, nub) import Data.Function (on) import Data.Maybe (fromJust) import qualified Data.ByteString.Lazy.Char8 as BS@@ -91,6 +91,7 @@ , csvField :: CSVField } | FieldError { csvField :: CSVField } | DuplicateHeader{ csvColsExpected :: !Int+ , csvHeaderSerial :: !Int , csvDuplicate :: !String } | NoData deriving (Eq,Show)@@ -126,10 +127,11 @@ beCareful (Left []) = [] deduplicate (Left (errs@(DuplicateHeader{}:_)):Right heads:rows) = - Right (reverse $ foldl replace [] heads)+-- Right (reverse $ foldl replace [] heads)+ Right (replaceInOrder errs (zip heads [0..])) : rows deduplicate rows = rows-+{- replace output header | headerName `elem` map csvFieldContent output = header{ csvFieldContent = headerName@@ -137,6 +139,14 @@ : output | otherwise = header: output where headerName = csvFieldContent header+-}+ replaceInOrder [] headers = map fst headers+ replaceInOrder _ [] = []+ replaceInOrder (d:dups) ((h,n):headers)+ | csvHeaderSerial d == n = h{ csvFieldContent = BS.pack+ (csvDuplicate d++"_"++show n) }+ : replaceInOrder dups headers+ | otherwise = h: replaceInOrder (d:dups) headers -- | The header row of the CSV table, assuming it is non-empty. csvTableHeader :: CSVResult -> [String]@@ -200,11 +210,17 @@ checkDuplicateHeaders :: CSVRow -> CSVResult -> CSVResult checkDuplicateHeaders row result =- let headers = [ csvFieldContent f | f@(CSVField{}) <- row ]- dups = headers \\ nub headers+ let headers = [ f | f@(CSVField{}) <- row ]+ dups = deleteFirstsBy ((==)`on`csvFieldContent)+ headers (nub headers) n = length headers in if null dups then result- else Left (map (DuplicateHeader n . BS.unpack) dups) : result+ else Left (map (\d-> DuplicateHeader+ { csvColsExpected = n+ , csvHeaderSerial = csvColNum d+ , csvDuplicate = BS.unpack (csvFieldContent d)})+ dups)+ : result @@ -358,7 +374,8 @@ ppCSVError (err@FieldError{}) = ppCSVField (csvField err) ppCSVError (err@DuplicateHeader{}) = "\nThere are two (or more) identical column headers: "++- show (csvDuplicate err)++"."+ show (csvDuplicate err)++"."+++ "\n Column number "++show (csvHeaderSerial err) ppCSVError (NoData{}) = "\nNo usable data (after accounting for any other errors)."
Text/CSV/Lazy/String.hs view
@@ -48,7 +48,7 @@ ) where import Data.List (groupBy, partition, elemIndex, intercalate, takeWhile- ,(\\), nub)+ ,deleteFirstsBy, nub) import Data.Function (on) import Data.Maybe (fromJust) @@ -87,6 +87,7 @@ , csvField :: CSVField } | FieldError { csvField :: CSVField } | DuplicateHeader{ csvColsExpected :: !Int+ , csvHeaderSerial :: !Int , csvDuplicate :: !String } | NoData deriving (Eq,Show)@@ -103,6 +104,7 @@ csvErrors :: CSVResult -> [CSVError] csvErrors r = concat [ v | Left v <- r ] -- | Extract the full table, including invalid rows, repaired with padding.+-- and de-duplicated headers. csvTableFull:: CSVResult -> CSVTable csvTableFull = map beCareful . deduplicate where beCareful (Right row) = row@@ -121,16 +123,25 @@ beCareful (Left []) = [] deduplicate (Left (errs@(DuplicateHeader{}:_)):Right heads:rows) =- Right (reverse $ foldl replace [] heads)+-- Right (reverse $ foldl replace [] heads)+ Right (replaceInOrder errs (zip heads [0..])) : rows deduplicate rows = rows-+{- replace output header | headerName `elem` map csvFieldContent output = header{ csvFieldContent=headerName++"_duplicate" } : output | otherwise = header: output where headerName = csvFieldContent header+-}+ replaceInOrder [] headers = map fst headers+ replaceInOrder _ [] = []+ replaceInOrder (d:dups) ((h,n):headers)+ | csvHeaderSerial d == n = h{ csvFieldContent =+ (csvDuplicate d++"_"++show n) }+ : replaceInOrder dups headers+ | otherwise = h: replaceInOrder (d:dups) headers -- | The header row of the CSV table, assuming it is non-empty. csvTableHeader :: CSVResult -> [String]@@ -194,11 +205,17 @@ checkDuplicateHeaders :: CSVRow -> CSVResult -> CSVResult checkDuplicateHeaders row result =- let headers = [ csvFieldContent f | f@(CSVField{}) <- row ]- dups = headers \\ nub headers+ let headers = [ f | f@(CSVField{}) <- row ]+ dups = deleteFirstsBy ((==)`on`csvFieldContent)+ headers (nub headers) n = length headers in if null dups then result- else Left (map (DuplicateHeader n) dups): result+ else Left (map (\d-> DuplicateHeader+ { csvColsExpected = n+ , csvHeaderSerial = csvColNum d+ , csvDuplicate = csvFieldContent d })+ dups)+ : result -- Reading CSV data is essentially lexical, and can be implemented with a@@ -248,6 +265,10 @@ simple s' (textRow s',1) [] cs where s' = incTableRow . incTextRow $! s {tableCol=1, textCol=1}+ simple s begin acc ('\r' :cs) = mkField s begin acc False :+ simple s' (textRow s',1) [] cs+ where s' = incTableRow . incTextRow $!+ s {tableCol=1, textCol=1} simple s begin [] ('"' :cs) = string (incTextCol $! s) begin [] cs simple s begin acc ('"' :cs) = mkError s begin "Start-quote not next to comma":@@ -341,7 +362,8 @@ ppCSVError (err@FieldError{}) = ppCSVField (csvField err) ppCSVError (err@DuplicateHeader{}) = "\nThere are two (or more) identical column headers: "++- show (csvDuplicate err)++"."+ show (csvDuplicate err)++"."+++ "\n Column number "++show (csvHeaderSerial err) ppCSVError (err@NoData{}) = "\nNo usable data (after accounting for any other errors)."
changelog.html view
@@ -13,6 +13,12 @@ </center> <hr> +<h3>Release 0.5</h3>+<ul>+<li> Bugfix when encountering CR-only line-endings.+<li> Bugfix when encountering multi-duplicate headers.+</ul>+ <h3>Release 0.4</h3> <ul> <li> First public release.
index.html view
@@ -198,8 +198,8 @@ <p> <b>Current released version:</b><br>-lazy-csv-0.4, release date 2013.02.25 --<a href="http://hackage.haskell.org/packages/lazy-csv">on Hackage</a>+lazy-csv-0.5, release date 2013.05.24 -+<a href="http://hackage.haskell.org/package/lazy-csv">on Hackage</a> <br> <ul>@@ -208,6 +208,7 @@ <p> <b>Older versions:</b><br>+lazy-csv-0.5, release date 2013.05.24 - Fifth release, public.<br> lazy-csv-0.4, release date 2013.02.25 - Fourth release, first public.<br> lazy-csv-0.3, release date 2011.12.12 - Third (non-public) release.<br> lazy-csv-0.2, release date 2011.10.11 - Second (non-public) release.<br>@@ -216,6 +217,8 @@ <hr> <center><h3><a name="news">Recent news</a></h3></center>+<p>+Version 0.5 fixes a bug when handling (rare) CR-only line-endings. <p> Version 0.4 is the first public release. <p>
lazy-csv.cabal view
@@ -1,5 +1,5 @@ Name: lazy-csv-Version: 0.4+Version: 0.5 License: BSD3 License-file: LICENCE-BSD3 Copyright: Malcolm Wallace, Ian Lynagh, and Well Typed LLP