2

我已经定义了以下 Parsec 解析器,用于将 csv 文件解析为字符串表,即[[String]]

--A csv parser is some rows seperated, and possibly ended, by a newline charater
csvParser = sepEndBy row (char '\n')
--A row is some cells seperated by a comma character
row = sepBy cell (char ',')
--A cell is either a quoted cell, or a normal cell
cell = qcell <|> ncell
--A normal cell is a series of charaters which are neither , or newline. It might also be an escape character
ncell = many (escChar <|> noneOf ",\n")
--A quoted cell is a " followd by some characters which either are escape charaters or normal characters except for "
qcell = do
    char '"'
    res <- many (escChar <|> noneOf "\"")
    char '"'
    return res
--An escape character is anything followed by a \. The \ will be discarded.
escChar = char '\\' >> anyChar

我真的不知道这些评论是否太多和烦人,是否有帮助。作为 Parsec 菜鸟,他们会帮助我,所以我想我会添加它们。

它工作得很好,但是有一个问题。它在表中创建一个额外的空行。因此,例如,如果我有一个包含 10 行的 csv 文件(即只有 10 行。最后没有空行*),则[[String]]结构的长度为 11,最后一个Strings 列表将包含 1 个元素。一个空的String(至少这是使用 打印时的样子show)。

我的主要问题是:为什么会出现这个额外的行,我能做些什么来阻止它?

我注意到的另一件事是,如果 csv 文件中的数据后面有空行,则这些行最终将成为String表中仅包含空行的行。我认为使用sepEndBy而不是sepBy会忽略多余的空行。不是这样吗?

*在十六进制编辑器中查看文本文件后,它似乎确实以换行符结尾,即使 vim 没有显示它......

4

1 回答 1

3

如果您希望每一行至少有一个单元格,您可以使用sepBy1代替sepBy. 这也应该停止将空行解析为一行。和之间的区别与和sepBy之间sepBy1的区别相同:该版本仅解析至少一个元素的序列。所以变成了这样:manymany11row

row = sepBy1 cell (char ',')

此外,通常的样式是sepBy1在中缀中使用:cell `sepBy1` char ','. 这读起来更自然:你有一个“用逗号分隔的单元格”而不是“用逗号分隔的单元格”。

编辑:如果您不想接受空单元格,则必须使用以下命令指定ncell至少具有一个字符many1

ncell = many1 (escChar <|> noneOf ",\n")
于 2012-07-23T19:36:38.397 回答