2012-10-04 15 views
2

我是Haskell和Parsec的新手---如果這個問題微不足道,我很抱歉。使用Parsec刪除文本達到特殊字符

我要解析的構成就像這行文字:在開始和結束時

<Text to be dropped> <special character (say "#")> <field 1> <comma> <field 2> 
<comma> <field 3> <special character 2 (say "%")> <Text to be dropped> 

我希望我的解析器放棄「的文字被丟棄」,並 保持字段的內容。我的主要問題是理解如何編寫一個解析器,將所有東西都放到某個特定的字符上。

似乎有用的庫中的解析器是anyChar,manyTill和oneOf,但我不明白如何將它們合併。我會很感激任何簡單的例子。

回答

3

在編寫Parsec代碼時,首先寫出您想要解析的語法,首先需要編寫的語法,因爲用Parsec編寫的解析器看起來非常像語法。

讓我們試試:

line ::= garbage '#' field ',' field ',' field '%' garbage 

在上面的生產,我們假設一個名爲garbage生產,其實際的定義取決於你真正想要什麼下降的文字。同樣,我們假設產品名稱爲field。現在,讓我們寫這篇生產出爲秒差距代碼:

line = do 
    garbage 
    char '#' 
    field1 <- field 
    char ',' 
    field2 <- field 
    char ',' 
    field3 <- field 
    char '%' 
    garbage 
    return (field1, field2, field3) 

此代碼讀取酷似BNF。本質區別是某些子產品的結果被命名,所以我們可以返回從這些結果構建的值(在本例中爲元組)。

現在我不知道你的垃圾概念是什麼,但爲了舉例,讓我們假設你的意思是任何空白。然後,你可以定義garbage如下:

garbage = many space 

(或者,恰巧秒差距已經解析零個或多個空格組合子叫spaces)。如果垃圾可能是除了#分隔符任何東西,那麼你可以說

garbage = many (noneOf "#") 

這條線將咀嚼所有輸入最多,但不包括第一個「#」。無論哪種方式,無論價值garbage產生的結果,因爲你沒有綁定一個名字的價值將被扔掉。

+0

我覺得noneOf只能通過解析一個字符,所以你需要將它與像許多相結合。還有skipMany,如果你只是扔掉結果,我認爲它更有效率。 –

+0

@ØrjanJohansen,啊,很好看,謝謝。 – macron

+0

非常感謝您的時間,這非常有用! – user1720555

1

或者,你可以使用應用性分析器:

import Control.Applicative 
import Text.Parsec 
import Text.Parsec.String 

type Field =()     --your type here 

field = string "()" *> pure() --your parser here 

parser :: Parser (Field, Field, Field) 
parser = manyTill anyChar (char '#') *> 
     ((,,) <$> (field <* char ',') 
       <*> (field <* char ',') 
       <*> (field <* char '%'))