【问题标题】:Why does FParsec not consume characters parsing a list separator?为什么 FParsec 不使用解析列表分隔符的字符?
【发布时间】:2018-06-02 03:13:18
【问题描述】:

下面的实际场景是虚构的。这个问题的目的是更多地了解 FParsec 在这里做了什么。

我正在解析由一个或多个空格字符 ' ' 分隔的字符串 (w)(x) 的列表。

我的列表xs 的解析器使用sepBy 和分隔符解析器isSeparator

isSeparator 基于manySatisfy 并且似乎正确地使用了空格。我相信当它解析两个在位置 3 结束的前导空格字符时,可以在下面的测试输出中看到这一点。

但是我在xs中使用它就失败了,如下图。

为什么会失败?处理可能是一个或多个空格的分隔符的好方法是什么?

open FParsec

let test p str =
    match run p str with
    | Success(result, _, p)   -> printfn "Success: %A position = %A" result p
    | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg

let str s = pstringCI s

let w = str "(w)"
let z = str "(z)"

let woz = w <|> z

let isSeparator = manySatisfy (fun c -> c = ' ')
let xs = sepBy woz isSeparator

test isSeparator "  (w)" // Success: "  " position = (Ln: 1, Col: 3)
test xs "(z) (w)"        // Failure: Error in Ln: 1 Col: 8
                         // (z) (w)
                         //        ^
                         // Note: The error occurred at the end of the input stream.                         
                         // Expecting: '(w)' (case-insensitive) or '(z)' (case-insensitive)

【问题讨论】:

  • 我不太确定问题是什么。解析器 xs 正确解析 wz 由单个空格分隔,因为这是您指定为分隔符的内容。解析器 x2 应该可以按预期工作:解析 wz 由多个空格分隔。
  • 天哪 - 我的错...代码格式错误。将编辑和更新。谢谢 Fyodor Soikin。
  • 现在已经编辑和更新了代码。

标签: f# fparsec


【解决方案1】:

发生这种情况是因为manySatisfy 匹配零个或多个 满足给定谓词的字符,关键字是“零”。这意味着,在输入的最后,isSeparator 实际上成功了,即使它不消耗任何字符。由于isSeparator 成功,sepBy 期望在分隔符之后找到另一个woz 实例。但是没有更多实例,所以sepBy 返回错误。

要验证这一点,请尝试解析wz 之间没有空格的输入:test xs "(z)(w)"。这应该打印“成功”,因为空分隔符是可以的。

要使isSeparator 始终使用至少一个字符并在找不到空格时失败,请使用many1Satisfy 而不是manySatisfy

let isSeparator = many1Satisfy (fun c -> c = ' ')
let xs = sepBy woz isSeparator

【讨论】:

  • 今天花了几个小时在这个问题上,“关键词是‘零’”是一个让我印象深刻的短语!谢谢。
  • 很高兴为您提供帮助。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多