2017-10-19 113 views
2

我使用(濫用)解析器進行一些字符串轉換,例如normalizeWS :: Parser String刪除重複的空格,並且normalizeCase將特定字符串映射爲小寫。我使用分析器,因爲輸入數據有一些結構,例如文字字符串必須保持不變。有沒有一種優雅的方式來提供一個解析器的輸出作爲下一個輸入,從而形成一個轉換管道? normalizeWS . normalizeCase(這當然不起作用)的東西?parsec:將一個解析器的輸出提供給另一個解析器

非常感謝提前!

+0

我不認爲你可以用這種方式編寫'Parser's,因爲它們都會從底層流中讀取。我認爲你可能會更好地將每個定義爲'String - > String',並且當你有一個'Parser String'時,你想規範化你可以'fmap(normalizeWS。normalizeCase)'。 – ryachza

回答

1

我用這個方法解決了這個問題...也許還有一個更優雅的方式

preprocessor :: Parser String 
preprocessor = normalizeCase `feeds` expandKettensatz `feeds` normalizeWs 

feeds :: Parser String -> Parser String -> Parser String 
feeds p1 p2 = do 
    s <- p1 
    setInput s 
    p2 
+0

這不會構成好:'feed p1 p2 >> p3'不像'消耗p1'消耗的東西,將消耗的結果傳遞給'p2',然後解析剩餘的未消耗的輸入爲'p3'會「 。要想解決這個問題並不容易,不幸的是,當然,修復這種特殊情況的最明顯的'getInput' /'setInput'體操只會讓bug更加微妙,而不是在所有情況下實際工作。 –

0

如果你有功能類似於

normalizeWhitespace :: Stream s m Char => ParsecT s u m String 
normalizeCase :: Stream s m Char => Set String -> Parsec s u m String 

你可以使用runParser>>=把它們結合在一起:

runBoth :: Stream s Identity Char => Set String -> SourceName -> s -> Either ParseError String 
runBoth wordSet src input = do 
    input <- runParser normalizeWhitespace() src input 
    runParser (normalizeCase wordSet)() src input 

但是這不會給你一個解析器,你可以和其他解析器一起鏈接。

這並不令人驚訝,因爲Parsec中的解析器組成都是關於構成在相同流上操作的解析器的 ,而這些解析器在 上操作不同的流。

擁有多個不同的流也很常見 - 使用a tokenization or lexing pass as input to parsing的輸出可以使得該流程更容易理解 ,但Parsec is a little easier to use out of the box as a direct parser (without lexing/tokenization)