2012-07-23 71 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