Skip to content

Commit 69d1442

Browse files
authored
parse newlines created in MacOS MS Excel (#55)
* parse newlines created in MacOS MS Excel * version bump to 1.0.0.2
1 parent 9ea646c commit 69d1442

File tree

6 files changed

+23
-10
lines changed

6 files changed

+23
-10
lines changed

changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
1.0.0.2
2+
* Fixed [#17](https://github.com/ozataman/csv-conduit/issues/17),
3+
where CSV created with Excel in Mac OS failed to parse due to its
4+
newline characters.
5+
16
1.0.0.1
27
* Removed dependencies: mmorph, monad-control, mtl,
38
unordered-containers, primitive

csv-conduit.cabal

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: csv-conduit
2-
version: 1.0.0.1
2+
version: 1.0.0.2
33
synopsis:
44
A flexible, fast, conduit-based CSV parser library for Haskell.
55

@@ -57,6 +57,7 @@ description:
5757
extra-source-files:
5858
changelog.md
5959
README.md
60+
test/test-mac-excel.csv
6061
test/test.csv
6162
test/Test.hs
6263

src/Data/CSV/Conduit/Parser/ByteString.hs

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,17 @@ csv s = do
5858
row :: CSVSettings -> Parser (Maybe (Row ByteString))
5959
row csvs = csvrow csvs <|> badrow
6060

61+
csvEndOfLine :: Parser ()
62+
csvEndOfLine = (word8 10 >> return ()) <|> (C8.string (B8.pack "\r\n") >> return ()) <|> (word8 13 >> return ())
6163

6264
badrow :: Parser (Maybe (Row ByteString))
6365
badrow = P.takeWhile (not . C8.isEndOfLine) *>
64-
(C8.endOfLine <|> C8.endOfInput) *> return Nothing
66+
(csvEndOfLine <|> C8.endOfInput) *> return Nothing
6567

6668
csvrow :: CSVSettings -> Parser (Maybe (Row ByteString))
6769
csvrow c =
6870
let rowbody = (quotedField' <|> field c) `sepBy` C8.char (csvSep c)
69-
properrow = rowbody <* (C8.endOfLine <|> P.endOfInput)
71+
properrow = rowbody <* (csvEndOfLine <|> P.endOfInput)
7072
quotedField' = case csvQuoteChar c of
7173
Nothing -> mzero
7274
Just q' -> try (quotedField q')

src/Data/CSV/Conduit/Parser/Text.hs

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,17 @@ csv s = do
5858
row :: CSVSettings -> Parser (Maybe (Row Text))
5959
row csvs = csvrow csvs <|> badrow
6060

61+
csvEndOfLine :: Parser ()
62+
csvEndOfLine = (char '\n' >> return ()) <|> (string (T.pack "\r\n") >> return ()) <|> (char '\r' >> return ())
6163

6264
badrow :: Parser (Maybe (Row Text))
6365
badrow = P.takeWhile (not . T.isEndOfLine) *>
64-
(T.endOfLine <|> T.endOfInput) *> return Nothing
66+
(csvEndOfLine <|> T.endOfInput) *> return Nothing
6567

6668
csvrow :: CSVSettings -> Parser (Maybe (Row Text))
6769
csvrow c =
6870
let rowbody = (quotedField' <|> field c) `sepBy` T.char (csvSep c)
69-
properrow = rowbody <* (T.endOfLine <|> P.endOfInput)
71+
properrow = rowbody <* (csvEndOfLine <|> P.endOfInput)
7072
quotedField' = case csvQuoteChar c of
7173
Nothing -> mzero
7274
Just q' -> try (quotedField q')

test/Test.hs

+7-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ tests =
3232
baseTests :: [Test]
3333
baseTests =
3434
[ testCase "mapping with id works" test_identityMap,
35-
testCase "simple parsing works" test_simpleParse,
35+
testCase "simple parsing works" (test_simpleParse testFile1),
36+
testCase "simple parsing works for Mac-Excel" (test_simpleParse testFile3),
3637
testCase "OrderedMap" test_orderedMap
3738
]
3839

@@ -74,9 +75,9 @@ test_identityMap = do
7475
f :: Row Text -> [Row Text]
7576
f = return
7677

77-
test_simpleParse :: IO ()
78-
test_simpleParse = do
79-
(d :: V.Vector (MapRow B.ByteString)) <- readCSVFile csvSettings testFile1
78+
test_simpleParse :: FilePath -> IO ()
79+
test_simpleParse fp = do
80+
(d :: V.Vector (MapRow B.ByteString)) <- readCSVFile csvSettings fp
8081
V.mapM_ assertRow d
8182
where
8283
assertRow r = v3 @=? (v1 + v2)
@@ -109,9 +110,10 @@ test_orderedMap = do
109110
csvSettings :: CSVSettings
110111
csvSettings = defCSVSettings {csvQuoteCharAndStyle = Just ('`', DontQuoteEmpty)}
111112

112-
testFile1, testFile2 :: FilePath
113+
testFile1, testFile2, testFile3 :: FilePath
113114
testFile1 = "test/test.csv"
114115
testFile2 = "test/test.csv"
116+
testFile3 = "test/test-mac-excel.csv"
115117

116118
readBS :: B.ByteString -> Int
117119
readBS = read . B.unpack

test/test-mac-excel.csv

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`Col1`,`Col2`,`Col3`,`Sum``A`,`2`,`3`,`5``B`,`3`,`4`,`7``Field using the quote char ``this is the in-quoted value```,`4`,`5`,`9`

0 commit comments

Comments
 (0)