我使用(濫用)解析器進行一些字符串轉換,例如normalizeWS :: Parser String
刪除重複的空格,並且normalizeCase
將特定字符串映射爲小寫。我使用分析器,因爲輸入數據有一些結構,例如文字字符串必須保持不變。有沒有一種優雅的方式來提供一個解析器的輸出作爲下一個輸入,從而形成一個轉換管道? normalizeWS . normalizeCase
(這當然不起作用)的東西?parsec:將一個解析器的輸出提供給另一個解析器
非常感謝提前!
我使用(濫用)解析器進行一些字符串轉換,例如normalizeWS :: Parser String
刪除重複的空格,並且normalizeCase
將特定字符串映射爲小寫。我使用分析器,因爲輸入數據有一些結構,例如文字字符串必須保持不變。有沒有一種優雅的方式來提供一個解析器的輸出作爲下一個輸入,從而形成一個轉換管道? normalizeWS . normalizeCase
(這當然不起作用)的東西?parsec:將一個解析器的輸出提供給另一個解析器
非常感謝提前!
我用這個方法解決了這個問題...也許還有一個更優雅的方式
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
這不會構成好:'feed p1 p2 >> p3'不像'消耗p1'消耗的東西,將消耗的結果傳遞給'p2',然後解析剩餘的未消耗的輸入爲'p3'會「 。要想解決這個問題並不容易,不幸的是,當然,修復這種特殊情況的最明顯的'getInput' /'setInput'體操只會讓bug更加微妙,而不是在所有情況下實際工作。 –
如果你有功能類似於
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)。
我不認爲你可以用這種方式編寫'Parser's,因爲它們都會從底層流中讀取。我認爲你可能會更好地將每個定義爲'String - > String',並且當你有一個'Parser String'時,你想規範化你可以'fmap(normalizeWS。normalizeCase)'。 – ryachza