【问题标题】:FParsec failing on optional parserFParsec 在可选解析器上失败
【发布时间】:2017-10-10 04:39:25
【问题描述】:

我目前正在学习 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,但是,我无法提供我想要的默认实体行为。

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

【问题讨论】:

    标签: parsing f# fparsec


    【解决方案1】:

    opt combinator 遵循与&lt;|&gt; 相同的规则;如果您查看&lt;|&gt; documentation,它提到如果第一个解析器失败没有更改解析器状态,则会尝试第二个解析器。 http://www.quanttec.com/fparsec/users-guide/parsing-alternatives.html 更详细。

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

    P.S.我对此进行了测试,它确实有效。将.&gt;&gt; 替换为pEntity 中的.&gt;&gt;?,然后运行您的代码会产生以下输出:

    Success: Entity "test"
    Success: Default
    

    【讨论】:

    • 所以它只会在解析器没有消耗任何输入并且被指示回溯的情况下才会尝试下一位?
    • 当您在该问题中说“它”时,我不清楚您指的是哪个组合子。如果您的意思是&lt;|&gt; 组合器,则删除短语“并且它已被指示回溯”,答案将是“是”。 &lt;|&gt; 组合器只会在第一个解析器失败没有消耗输入时尝试下一位。从&lt;|&gt; 组合器的角度来看,第一个解析器是立即失败,还是尝试了某些东西然后回溯,这无关紧要。 &lt;|&gt; 所知道的只是“我尝试了第一个解析器,并且流仍然处于相同的状态”。我将在下一条评论中联系.&gt;&gt;?
    • 如果您问题中的“它”一词表示.&gt;&gt;? 组合子,那么答案是“否”。 .&gt;&gt;? 组合器将首先尝试下一位,如果下一位失败,它将回溯到尝试第一位之前的解析器状态。其他以? 结尾的组合子变体都遵循类似的规则:它们都尝试第二位,如果失败,则回溯到尝试第一位之前的状态。
    • 最后,如果您询问opt 组合器的行为,那么它遵循与&lt;|&gt; 相同的规则,除了opt 不采用“下一位”。这就像&lt;|&gt;,其中“下一位”是“返回None 作为此解析器的成功结果”。
    猜你喜欢
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多