2012-07-23 55 views
2

我已经定义了follwing秒差距解析器解析CSV文件转换成字符串的表,即[[String]]秒差距CSV解析器解析额外的行

--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 noob他们会帮助我,所以我想我会添加它们。

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

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

我注意到的另一件事是,如果在csv文件中的数据之后有空行,这些行将最终为表中只包含空的String的行。我认为使用sepEndBy而不是sepBy会使多余的空行被忽略。这不是这种情况吗?

*看着十六进制编辑器的文本文件后,它似乎的确实际上换行符结束,尽管VIM不显示它...

回答

2

如果你想每行有至少有一个单元格,您可以使用sepBy1而不是sepBy。这也应该停止空行被解析为一行。 sepBysepBy1之间的差异与manymany1之间的差异相同:1版本仅解析至少一个元素的序列。所以row变成这样:

row = sepBy1 cell (char ',') 

此外,一贯的作风是使用中缀sepBy1cell `sepBy1` char ','。这更自然地阅读:你有一个“用逗号分开的单元”,而不是“用逗号分隔”。

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

ncell = many1 (escChar <|> noneOf ",\n") 
+0

对不起。我没有说我的问题完全正确。事实证明,额外的行和空行行实际上在解析时不会变为空列表。相反,它们最终包含1个看起来是空的“String”的元素。我会改变我的问题反映这一点。 您的解决方案在任何情况下都无效。可能是因为我没有正确说明问题。但我应该使用'sepBy1',所以谢谢你的帮助:) – 2012-07-23 20:37:26

+2

@andvin问题是'many'和'sepBy'可以不消耗,而终止'sep'是'sepEndBy'的可选项。当达到最后的'\ n''时,解析器尝试用剩余的输入读取另一行。 'row'试图解析第一个单元格。 'ncell'用'“”成功,行查找'',','找不到,用一个单元'[“”]'成功。 'rows'检查一个''\ n',发现没有,并且最后一行成功['“]]。如果在'ncell'中使用'many1',但在行中不使用'sepBy1',则必须在emty输入中同时使'cell'和'row'失效,以摆脱最后一个空行('[]')。 – 2012-07-23 21:04:51

+0

谢谢!这解决了这个问题。但是现在我不能有空单元,但是我可以看到如何区分只有一个空单元的空行和行是不可能的。但也许可以用一个空单元区分行,而最后一个不存在的行是可能的?也许如果我用'sepBy'而不是'sepEndBy'?我的意思是,应该可以区分空行和EOF之间的区别吗? 无论如何,我想我应该看看csv是如何定义的,以及它是否允许不同长度的行。 – 2012-07-24 21:08:45