2013-07-25 42 views
1

我已經面臨秒差距解析器的不明確的行爲,所以我想parsre字符串作爲同一秒差距解析器失敗的many1和manyTill組合子

> <CdId> 
1 

> <Mol Weight> 
270.2369 

> <Formula> 
C15H10O5 

> <LOG_ER_RBA> 
-0.36 

> <ACTIVITY> 
1 

我寫了一個解析器

parseProperties = do  
     skipMany1 newline 
     char '>' >> spaces >> char '<' 
     propName <- many1 (noneOf ">") 
     char '>' 
     newline 
     propValue <- many1 (noneOf "\n") 
     return (propName,propValue) 

這個解析器出色地解析一個項目,並且還能夠解析幾個:

parseTest (count 5 parseProperties) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

結果

[("CdId","1"),("Mol Weight","270.2369"),("Formula","C15H10O5"),("LOG_ER_RBA","-0.36"),("ACTIVITY","1")] 

但是我發現沒有辦法來解析性能的隨機數。如果我嘗試

parseTest (many1 parseProperties) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

parseTest (manyTill parseProperties (try eof)) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

解析器失敗

parse error at (line 17, column 1): 
unexpected end of input 
expecting new-line or ">" 

但是,如果我用anyChar分析器,它沒有失敗。

parseTest (manyTill anyChar (try eof)) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

"\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 
+0

我可以建議'many1(noneOf「>」)'是不好的做法。謹慎使用'noneOf' - 決定什麼是允許的,而不是什麼不是。你說過,'propertyName'是任何不是'>'的東西。這允許一個名爲'%^ $ \ t 5&/ \ n \ n AndrewC

回答

2

parseProperties解析器在您的示例中執行多次,直到 eof遇到。問題是parseProperties在你的例子中並沒有消耗 尾隨的空白,所以在解析最後一個標記之後, 剩餘的字符串是"\n\n",這不會觸發你的終止 條件,因爲它不是輸入的結尾。這導致parseProperties 再次嘗試,它會消耗空白,但嘗試 吃'>'時失敗。

嘗試修改您的parseTest以下

test = "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

parseTest (manyTill parseProperties $ try (skipMany newline >> eof)) test 

這改掉檢查前剝離前述空格,如果它是在端輸入的 。

+0

謝謝,它解決了這個問題 –

1

萬一 「\ n」 的數量是隨機的,我會用這個版本(而不是增加額外的解析器):

parseProperties :: Parser (String,String) 
parseProperties = do 
    skipMany newline -- optional newline(s) 
    char '>' >> spaces >> char '<' 
    propName <- many1 (noneOf ">") 
    char '>' 
    newline 
    propValue <- many1 (noneOf "\n") 
    skipMany newline -- optional newline(s) 
    return (propName,propValue) 

我想這個版本:

parseTest (many1 parseProperties) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n><Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

而且得到:

[("CdId","1"),("Mol Weight","270.2369"),("Formula","C15H10O5"),("LOG_ER_RBA","-0.36"),  ("ACTIVITY","1")]