質問
私は最後の要素が、すべて1つのパーサによって解析される必要がある場所を解析する必要がリストを持って、そして最後の要素は、別のパーサで解析する必要があります。
a = "p1 p1b ... p2"
or
a = "p2"
もともと、私が試した
parser = do parse1 <- many parser1
parse2 <- parser2
return AParse parse1 parse2
問題はparse1がparse2入力を消費することができるということです。だから、parse1常にリスト全体を消費し、そして何もparse2を残しています。
parse2を適用し、文字列の最後の要素以外のすべてにparse1を適用すると言う、とする方法はありますか?
解決
いかがます:
parseTrain car caboose = choice
[ fmap (:[]) $ try (caboose `endBy` eof),
, liftM2 (:) car (parseTrain car caboose)
[
それは作るので、私は、このパーサは、組成ないEOFのバグ。即ちあなたが言うことができませんでした。
char '(' >> parseTrain p1 p2 >> char ')'
このcompsitionallyを行うと、パーサーのために非常に困難です。それはどのようにあらゆる機会にしようとし、それが失敗した場合に見ずに、「)」文字に移動する知っていることになっていますか?そうすることで、時間を指数関数可能性があります。
あなたはそれが組成する必要がある場合は、、あなたの問題は、あなたが利用することができ、いくつかの付加的な構造を持っているのですか?あなたは、たとえば、すべての要素のリストを解析し、事実の後、最後の1を処理することはできますか?
他のヒント
それはそうのように定義されているので、あなたがparser1
を考慮することができた場合:
parser1 = (try parser2) <|> parser1extra
すると問題は、後に終了しなければなりませんparser1extra
またはparser2
のリストになります。あなたはそれをコーディングすることができます。
parserList =
liftM2 (:) (try parser1extra) parserList
<|>
liftM2 (:) (try parser2) (option [] parserList)
これらのパーサは任意のプレフィックスの重複がある場合は、またはに応じてtry
コールを必要としない場合があります。
たくない場合は、代わりにあなたのAParseのデータは、その後、あなたはそれをこのように書き直すことができます:
parserList =
do
a <- try parser1extra
prefix a parserList
<|>
do
a <- try parser2
option (AParse [] a) (prefix a parserList)
where prefix a p = do
(AParse as t) <- p
return $ (AParse (a:as) t)
あるいは、完全な例:
import Control.Monad
import Text.ParserCombinators.Parsec
parseNum = do { v <- many1 digit; spaces; return v }
parseWord = do { v <- many1 letter; spaces; return v }
parsePart = parseNum <|> parseWord
parsePartListEndingInWord =
liftM2 (:) (try parseNum) parsePartListEndingInWord
<|>
liftM2 (:) (try parseWord) (option [] parsePartListEndingInWord)
実際には、呼び出しはparseNum
として、この場合に必要とされていないしようとすると何の共通のプレフィックスと一致していないparseWord
。実際parsePartListEndingInWord
を参照しないように注意してくださいparsePart
が、その代わりに、parsePart
の定義を構成する2つのオプション
(オリジナル答え、多少異なった状況を解決する:)
どのようなものについて:
parserTest = between (char '[') (char ']') $ do
p1s <- try parser1 `endBy` char ','
p2 <- parser2
return $ AParse p1s p2
アップparseTestにあなたのパーサの外に句読点を撮影し、あなたがあなたのために仕事をするためにコンビネータのbetween
とendBy
を使用することができます。最後に、try
はparser1
とparser2
は共通のプレフィックスに一致する場合、endBy
は共通のプレフィックスの先頭に正しいフルバックアップを実行するようにあります。
あなたのパーサによっては、あなたがあなたのサブパーサ内の句読点マッチングを残すことができ、あなたが必要とするすべてのtry
周りparser1
なる可能性があります:
parseTest = do parse1 <- many (try parser1)
parse2 <- parser2
return AParse parse1 parse2
私は一種の二つのアプローチを組み合わせます
parserList = try (do a <- parser2
eof
return $ AParse [] a)
<|>
do a <- parser1
prefix a parserList
where
prefix a p = do
(AParse as t) <- p
return $ AParse a:as t
私は、これが私の目的のために働くだろうと思います。 ありがとう!
これは、トリックを行います。
parser1 `manyTill` (try parser2)