2017-10-19 3 views
2

パーサーを使用して文字列変換を行います。 normalizeWS :: Parser Stringは重複する空白を削除し、normalizeCaseは特定の文字列を小文字にマップします。私はパーサーを使用します。なぜなら、入力データに構造体があります。例えば、リテラル文字列は変換されずに残されなければなりません。 1つのパーサの出力を次の入力に渡して変換パイプラインを形成するエレガントな方法はありますか? normalizeWS . normalizeCaseの静脈の中の何か(どちらがうまくいくのですか?)parsec:あるパーサーの出力を別のパーサーに渡す

事前に感謝します。

+0

「Parser」は、両方とも基本ストリームから読み込むので、このように構成することはできません。私はそれぞれを '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''に渡し、残りの未消費の入力を' 。そして、どちらにせよ、悲しいことに、それを修正することは容易ではありません。確かに、この特定のケースを修正するための最も明白な 'getInput' /' setInput'体操は、すべての場合に実際に作業するのではなく、バグをより微妙にします。 –

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)です。