FParsec在可选解析器上失败

问题描述:

我目前正在学习FParsec库,但遇到了一个问题。当我想要解析一个可选字符串并继续正常解析时,FParsec将在可选解析器上返回一个致命错误,而不是像我期望的那样返回None。下面的工作代码示例说明了我的观点:FParsec在可选解析器上失败

open System 
open FParsec 

type AccountEntity = 
    | Default 
    | Entity of string 

let pEntity = 
    let isEntityFirstChar c = isLetter c 
    let isEntityChar c = isLetter c || isDigit c 
    (many1Satisfy2L isEntityFirstChar isEntityChar "entity") .>> skipString "/" 

let pOptEntity = 
    opt pEntity 
    |>> (fun optEntity -> 
       match optEntity with 
       | Some entity -> Entity entity 
       | None -> Default) 

[<EntryPoint>] 
let main argv = 
    printfn "%A" (run pOptEntity "test/account:subaccount") //works 
    printfn "%A" (run pOptEntity "account:subaccount") //crashes 
    Console.ReadLine() |> ignore 
    0 // return an integer exit code 

我期望的行为是在不设置实体pOptEntity返回一个Default实体。但是,相反,我得到以下错误:

Failure: 
Error in Ln: 1 Col: 8 
account:subaccount 
    ^
Expecting: '/' 

不应该opt提供我所描述的,继续解析帐户字符串为正常还是我不正确的方式处理这个问题?我看了一下attempt,但是,我不能像我想要的那样提供默认的实体行为。

非常感谢您的帮助,谢谢。

opt combinator遵循与<|>相同的规则;如果您查看<|> documentation,它会提到如果第一个解析器在未更改解析器状态时失败,则尝试第二个解析器。 http://www.quanttec.com/fparsec/users-guide/parsing-alternatives.html进入更多细节。

在这里,.>>? combinator是你想在你的pEntity解析器中使用的。将.>>替换为.>>?,您将拥有一个pEntity解析器,如果它后面没有跟随/,将回溯到它尝试的内容的开头并且不会消耗输入。这将允许opt组合器按设计运行。

P.S.我测试了这个,它工作。更换.>>.>>?pEntity,然后运行代码产生了以下的输出:

Success: Entity "test" 
Success: Default 
+0

所以它只会尝试下位,如果解析器没有任何消耗输入其已经被指示要走回头路? –

+0

我不清楚你在那个问题中说“它”时的意思。如果你的意思是''combinator,那么删除短语“它已被指示回溯”,答案将是“是”。 ''combinator只会尝试下一位,如果第一个解析器失败*没有消费输入*。无论是第一个解析器立即失败,还是尝试了某种东西然后回溯,与组合器的观点无关。所有''知道的是“我尝试了第一个解析器,并且流仍然处于相同的状态”。我会在下一条评论中提到'。>>?'。 – rmunn

+0

如果您的问题中的“it”一词表示'。>>?'combinator,那么答案是“否”。 '。>>?'组合器将首先尝试下一位,如果下一位失败,它将在第一位尝试*之前回溯到解析器状态*。以'?'结尾的其他组合变体都遵循类似的规则:它们都尝试第二位,如果失败,则返回到第一位尝试之前的状态。 – rmunn