8

最後の要素を除くすべてを1つのパーサーで解析する必要があり、最後の要素を別のパーサーで解析する必要があるリストを解析する必要があります。

a = "p1 p1b ... p2"
or
a = "p2"

もともと試しました

parser = do parse1 <- many parser1
            parse2 <- parser2
            return AParse parse1 parse2

問題は、parse1がparse2入力を消費する可能性があることです。したがって、parse1は常にリスト全体を消費し、parse2には何も残しません。

文字列の最後の要素以外のすべてにparse1を適用してから、parse2を適用すると言う方法はありますか?

4

4 に答える 4

2

あなたがparser1そのように定義されるように因数分解することができるならば:

parser1 = (try parser2) <|> parser1extra

次に、問題はリストになるparser1extraparser2、後で終了する必要があります。次のようにコーディングできます。

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と一致しないため、tryの呼び出しは必要ありません。実際には参照していませんが、代わりに、の定義を構成する2つのオプションにparseWord注意してください。parsePartListEndingInWordparsePartparsePart


(元の答え、多少異なる状況を解決する:)

次のようなものはどうですか?

parserTest = between (char '[') (char ']') $ do
    p1s <- try parser1 `endBy` char ',' 
    p2 <- parser2
    return $ AParse p1s p2

パーサーから句読点を取り出してparseTestに入れると、コンビネーターを使用betweenendByて作業を行うことができます。最後に、共通プレフィックスと一致するtry場合、共通プレフィックスの先頭への正しい完全バックアップを実行するためにあります。parser1parser2endBy

パーサーによっては、句読点をサブパーサー内に一致させたままにしておくことができます。必要なのは、try周りだけparser1です。

parseTest = do parse1 <- many (try parser1)
               parse2 <- parser2
               return AParse parse1 parse2
于 2010-03-15T16:51:52.537 に答える
2

どうですか:

parseTrain car caboose = choice
    [ fmap (:[]) $ try (caboose `endBy` eof), 
    , liftM2 (:) car (parseTrain car caboose) 
    [

eofは、このパーサーを構成的ではないものにするので、私を悩ませます。つまり、あなたは言うことができませんでした:

char '(' >> parseTrain p1 p2 >> char ')'

これを構成的に行うことは、パーサーにとって非常に困難です。あらゆる機会に試みて失敗するかどうかを確認せずに、char')'に進むことをどのように知る必要がありますか?そうすることで、指数関数的な時間が発生する可能性があります。

構成的である必要がある場合、問題には利用できる追加の構造がありますか?たとえば、すべての要素のリストを解析して、事後に最後の要素を処理できますか?

于 2010-03-15T20:44:29.523 に答える
0

私は2つのアプローチを組み合わせました。

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

これは私の目的には役立つと思います。ありがとう!

于 2010-03-15T22:04:27.480 に答える
0

これでうまくいきます:

parser1 `manyTill` (try parser2)
于 2010-03-22T22:11:34.353 に答える