我有需要解析其中所有,但最后一个元素需要由一个解析器解析的列表,以及最后一个元素需要由另一解析器解析。

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

最初我试图

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

的问题是,parse1可以消耗parse2输入。所以parse1总是消耗约占整个列表,并留下parse2什么也没有。

有没有办法说申请parse1的一切,除了在字符串中的最后一个元素,然后应用parse2?

有帮助吗?

解决方案

如何:

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

在EOF的错误我,因为这使得这个解析器没有组成。即你不能说:

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

这样做compsitionally是非常难的解析器。它应该是怎样知道要移动到符“)”,而不会在每一个机会尝试,如果失败看?这样做可能会指数时间。

如果您需要的是组合的,贵的问题有一些额外的结构,你可以利用?你能,例如,解析所有元素的列表,然后处理事后的最后一个?

其他提示

如果使得像这样定义可以因素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)

其实,呼叫尝试不需要在这种情况下,parseNumparseWord匹配没有共同的前缀。请注意,parsePartListEndingInWord实际上并没有引用parsePart,而是两个选项构成parsePart的定义


(原来的答复,解决一个稍微不同的情况:)

如何是这样的:

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

以标点符号你的解析器和成parseTest允许您使用组合程序betweenendBy做的工作适合你。最后,try有这样如果parser1parser2匹配一个共同的前缀,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)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top