Haskell parsec解析字符串项

Haskell parsec解析字符串项,haskell,parsec,Haskell,Parsec,我有一个需要解析的列表,其中除最后一个元素外的所有元素都需要由一个解析器解析,最后一个元素需要由另一个解析器解析 a = "p1 p1b ... p2" or a = "p2" 最初我试过了 parser = do parse1 <- many parser1 parse2 <- parser2 return AParse parse1 parse2 parser=do parse1如果可以将parser1因子化,则定义如下: pa

我有一个需要解析的列表,其中除最后一个元素外的所有元素都需要由一个解析器解析,最后一个元素需要由另一个解析器解析

a = "p1 p1b ... p2"
or
a = "p2"
最初我试过了

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

parser=do parse1如果可以将
parser1
因子化,则定义如下:

parser1 = (try parser2) <|> parser1extra
您可能需要也可能不需要
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)
将标点符号从解析器中取出,然后放到parseTest中,这样您就可以使用组合符
介于
endBy
之间来为您完成这项工作。最后,如果
try
parser1
parser2
匹配公共前缀,
endBy
将执行到公共前缀开头的正确完整备份

根据解析器的不同,您可以在子解析器中保留匹配的标点符号,您所需要的可能就是a
try
around
parser1

parseTest = do parse1 <- many (try parser1)
               parse2 <- parser2
               return AParse parse1 parse2
parseTest=do parse1怎么样:

parseTrain car caboose = choice
    [ fmap (:[]) $ try (caboose `endBy` eof), 
    , liftM2 (:) car (parseTrain car caboose) 
    [
eof让我很烦,因为这使得这个解析器不是组合的。也就是说,你不能说:

char '(' >> parseTrain p1 p2 >> char ')'
对于解析器来说,以兼容的方式执行此操作非常困难。它如何知道如何继续使用char'),而不试图抓住每一个机会,看看是否失败?这样做可能会延长时间


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

我有点结合了这两种方法:

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

parserList=try(执行a这将实现以下技巧:

parser1 `manyTill` (try parser2)

我在问题中犯了一个错误,并说我有一个项目列表。我应该说我有一个项目字符串。对此很抱歉。我在问题中进行了更正。代码中的第二个示例不起作用,因为parser1将使用整个字符串。感谢您提供的代码。parser1extra不会使用所有字符串吗?idea认为parser1extra只会解析那些应该在parser1中的东西,但不匹配parser2。因此,parser1extra只匹配parser2不匹配的地方。
char '(' >> parseTrain p1 p2 >> char ')'
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)