f# - FParsec:如何从错误消息中省略 `many` 解析器失败

标签 f# parser-combinators fparsec

考虑这个将数字字符串转换为 int 的解析器s:

let toInt (s:string) = 
    match Int32.TryParse(s) with
    | (true, n) -> preturn n
    | _         -> fail "Number must be below 2147483648"

let naturalNum = many1Chars digit >>= toInt <?> "natural number"

当我在非数字字符串上运行它时,比如 "abc"它显示了正确的错误信息:

Error in Ln: 1 Col: 1
abc
^
Expecting: natural number

但是当我给它一个超过 int 的数字字符串时range 它给出了以下适得其反的信息:

Error in Ln: 1 Col: 17
9999999999999999
                ^
Note: The error occurred at the end of the input stream.
Expecting: decimal digit
Other error messages:
  Number must be below 2147483648

主要留言"Expecting: decimal digit"没有意义,因为我们已经有很多数字了。

有没有办法摆脱它,只显示"Number must be below 2147483648" ?

完整示例:
open System
open FParsec

[<EntryPoint>]
let main argv =
    let toInt (s:string) = 
        match Int32.TryParse(s) with
        | (true, n) -> preturn n
        | _         -> fail "Number must be below 2147483648"

    let naturalNum = many1Chars digit >>= toInt <?> "natural number"

    match run naturalNum "9999999999999999" with
    | Failure (msg, _, _) -> printfn "%s" msg
    | Success (a, _, _)   -> printfn "%A" a

    0

最佳答案

我认为这里问题的根源在于这是一个非语法问题,它不适合前瞻解析器的模型。如果您可以以句法方式表达“太多数字”,那么解析器也很有意义,但实际上它会返回并尝试消耗更多输入。因此,我认为最干净的解决方案是在解析后在单独的 channel 中进行 int 转换。

也就是说,FParsec 似乎足够灵活,您仍然应该能够一起破解它。这符合你的要求,我认为:

let naturalNum: Parser<int, _> =
    fun stream ->
        let reply = many1Chars digit stream
        match reply.Status with
            | Ok ->
                match Int32.TryParse(reply.Result) with
                | (true, n) -> Reply(n)
                | _         -> Reply(Error, messageError "Number must be below 2147483648")                
            | _ ->
                Reply(Error, reply.Error)

或者,如果您想要“自然数”错误消息而不是“十进制数字”,请将最后一行替换为:
Reply(Error, messageError "Expecting: natural number")

关于f# - FParsec:如何从错误消息中省略 `many` 解析器失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56300298/

相关文章:

f# - 了解 F# 组合运算符

c# - 如何在 .NET 中创建值类型集合?

Scala 解析器组合器将字符列表转换为字符串

parsing - 为什么我的递归 FParsec 解析器在解析嵌套数组时会抛出异常?

f# - 空格敏感 FParsec

for-loop - 避免 F# 中的 for 循环

f# - 我可以在不提供示例的情况下使用 CsvProvider 编写 header 吗?

f# - FParsec:回溯 `sepBy`

Scala Combinators JavaTokennParsers 预期为 '||' 但找到 '>'

F#、FParsec 和更新 UserState