f# - 如果 "till"解析器以空格开头,为什么 manyCharsTill 组合器不起作用?

标签 f# parser-combinators fparsec

我尝试解析类似 xml 的标签(但不是正确的 xml 文档..):
目标是在没有开头或结尾空格的情况下返回“法兰宽度”,而是使用内部空格。

open FParsec

let testParser =
    pstring "<desc>" .>>. spaces
    >>. manyCharsTill anyChar (spaces .>>. pstring "</desc>")

run testParser "<desc> Flange width </desc>"

如果我理解解析器组合器的预期结果:

保持吞下字符的 anyChar 解析器单元“直到”解析器,它寻找空格,然后是结束标记成功。

实际发生的情况是,“直到”解析器在“宽度”之前的空间上失败(应该如此),但会使 manyTill 解析器短路,而不是让 anyChar 吞下该空间并继续前进。

输出:
val it : ParserResult<string,unit> =
  Failure:
Error in Ln: 1 Col: 15
<desc> Flange width </desc>
              ^
Expecting: '</desc>'

我没有得到什么?或者这里的惯用解决方案是什么?

最佳答案

问题是spaces解析成功并将流移动到 w 的开头. pstring "</desc>"然后失败。

最终结果是endp解析器失败了,但它改变了状态(我们已经移过了空格)。您希望解析器失败并且不更改状态(在空格之前)。 manyTill 的文档(由 manyCharsTill 引用)解释一下:

The parser manyTill p endp repeatedly applies the parser p for as long as endp fails (without changing the parser state).



您可以使用 .>>.? operator 来做到这一点。 :

The parser p1 .>>.? p2 behaves like p1 .>>. p2, except that it will backtrack to the beginning if p2 fails with a non‐fatal error and without changing the parser state, even if p1 has changed the parser state.



所以这个:

let testParser =
    pstring "<desc>" .>>. spaces
    >>. manyCharsTill anyChar (spaces .>>.? pstring "</desc>")

this fiddle用于工作演示。

关于f# - 如果 "till"解析器以空格开头,为什么 manyCharsTill 组合器不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57291144/

相关文章:

f# - 让 FParsec 拒绝不匹配的开始结束标签?

csv - 如何为 F# 中的类型生成 CSV 读取器/写入器?

c++ - 关于如何将 F# 代码与 native C++ 集成的任何想法?

rust - 使用 nom 匹配模板过滤器表达式

parsing - 如何在 monad 转换器解析器组合器中限制回溯

rust - 如何使用 nom 吞噬字符串直到分隔符或结尾?

error-handling - 代表 F# 中失败的受歧视联合的优雅解决方案

python - 相当于 Python 中 F# 的 Seq.scan() 方法?

parsing - FParsec 中的示例语法超出了示例范围?

f# - 使用ParserResult