如果“耕种”解析器以空格开头,为什么很多CharsTill组合器都不起作用?

时间:2019-07-31 12:50:11

标签: 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解析器可以继续吞下char单元,而“ till”解析器会先查找空格,后跟end标记。

实际上发生的是,“耕种”解析器在“宽度”之前的空间上失败了(应该如此),但使manyTill解析器短路了,而不是让anyChar吞噬了该空间并继续。

输出:

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

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

1 个答案:

答案 0 :(得分:4)

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

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

  

只要manyTill p endp失败(不更改解析器状态),解析器p就会反复应用解析器endp

您可以使用.>>.? operator

  

解析器p1 .>>.? p2的行为与p1 .>>. p2相似,不同之处在于,如果p2因非致命错误而失败并且不更改解析器状态,即使{{{ 1}}更改了解析器状态。

因此,这是

p1

有关有效的演示,请参见this fiddle