f# - 为什么 FParsec 不使用解析列表分隔符的字符?
问题描述
下面的实际场景是虚构的。该问题的目的是更多地了解 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)
解决方案
发生这种情况是因为manySatisfy
匹配零个或多个满足给定谓词的字符,关键字是“零”。这意味着,在输入的最后,isSeparator
实际上成功了,即使它不消耗任何字符。并且既然isSeparator
成功了,就期待在分隔符之后sepBy
找到另一个实例。woz
但是没有更多的实例,所以sepBy
返回一个错误。
w
要验证这一点,请尝试解析和z
:之间没有空格的输入test xs "(z)(w)"
。这应该打印“成功”,因为空分隔符是可以的。
要isSeparator
始终使用至少一个字符并在找不到空格时失败,请使用many1Satisfy
代替manySatisfy
:
let isSeparator = many1Satisfy (fun c -> c = ' ')
let xs = sepBy woz isSeparator
推荐阅读
- asp.net-core - 当 API ResponseCache NoStore = true 时,HTTP 请求是否被缓存?在特定的 API 端点上
- java - 从List构建树关系图的有效方法
- reactjs - 如何用“链接”包装每个 antd 表行?
- visual-studio-2019 - 在 VS2019 中从 VS 2017 恢复编辑器颜色
- sql-server - 需要根据数据的值将数据透视到 MS SQL 中的对应列
- c# - 根据值获取渐变中的颜色值
- python - 如何检查页面是否已被访问?(我在用户模型上使用了一个数组字段,我正在尝试在其中添加页面 ID)
- reactjs - 在 React select 中使用枚举
- javascript - 如何在 Javascript 中创建准确的 setTimeout(不是间隔)?
- c# - Odata 不支持“GroupBy”方法