FParsec在可选解析器

时间:2017-10-10 04:39:26

标签: parsing f# fparsec

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

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,但是,我不能像我想要的那样提供默认的实体行为。

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

1 个答案:

答案 0 :(得分:2)

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