@@ -16,13 +16,11 @@ Conversion from CSV to a 'Pandoc' table.
1616-}
1717module Text.Pandoc.Readers.CSV ( readCSV ) where
1818import Prelude
19−import Control.Monad (guard)
2019import Data.Text (Text)
2120import qualified Data.Text as T
21+import Text.Pandoc.CSV (parseCSV, defaultCSVOptions)
2222import Text.Pandoc.Definition
2323import qualified Text.Pandoc.Builder as B
24−import Text.Parsec
25−import Text.Parsec.Text (Parser)
2624import Text.Pandoc.Class (PandocMonad)
2725import Text.Pandoc.Shared (crFilter)
2826import Text.Pandoc.Error
@@ -34,73 +32,15 @@ readCSV :: PandocMonad m
3432 -> Text -- ^ Text to parse (assuming @'\n'@ line endings)
3533 -> m Pandoc
3634readCSV _opts s = do
37− case parse pCSV "input" (crFilter s) of
35+ case parseCSV defaultCSVOptions (crFilter s) of
3836 Right (r:rs) -> return $ B.doc $ B.table capt (zip aligns widths) hdrs rows
3937 where capt = mempty
4038 numcols = length r
41− hdrs = map (B.plain . B.text) r
42− rows = map (map (B.plain . B.text)) rs
39+ toplain = B.plain . B.text . T.strip
40+ hdrs = map toplain r
41+ rows = map (map toplain) rs
4342 aligns = replicate numcols AlignDefault
4443 widths = replicate numcols 0
4544 Right [] -> return $ B.doc mempty
4645 Left e -> throwError $ PandocParsecError s e
4746
48−{- from RFC 4180
49−
50− The ABNF grammar [2] appears as follows:
51−
52− file = [header CRLF] record *(CRLF record) [CRLF]
53−
54− header = name *(COMMA name)
55−
56− record = field *(COMMA field)
57−
58− name = field
59−
60− field = (escaped / non-escaped)
61−
62− escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
63−
64− non-escaped = *TEXTDATA
65−
66− COMMA = %x2C
67−
68− CR = %x0D ;as per section 6.1 of RFC 2234 [2]
69−
70− DQUOTE = %x22 ;as per section 6.1 of RFC 2234 [2]
71−
72− LF = %x0A ;as per section 6.1 of RFC 2234 [2]
73−
74− CRLF = CR LF ;as per section 6.1 of RFC 2234 [2]
75−
76− TEXTDATA = %x20-21 / %x23-2B / %x2D-7E
77−-}
78−
79−pCSV :: Parser [[Text]]
80−pCSV = many pRecord
81−
82−pRecord :: Parser [Text]
83−pRecord = do
84− x <- pField
85− xs <- many $ pComma >> pField
86− () <$ newline <|> (guard (not (T.null x) || not (null xs)) >> eof)
87− return (x:xs)
88−
89−pField :: Parser Text
90−pField = pEscaped <|> pUnescaped
91−
92−pComma :: Parser Char
93−pComma = char ','
94−
95−pUnescaped :: Parser Text
96−pUnescaped = T.strip . T.pack <$> many (noneOf "\n\r\",")
97−
98−pEscaped :: Parser Text
99−pEscaped = do
100− char '"'
101− t <- T.pack <$> many (pDoubledQuote <|> noneOf "\"")
102− char '"'
103− return t
104−
105−pDoubledQuote :: Parser Char
106−pDoubledQuote = try $ char '"' >> char '"'