F# 为什么';t如果;直到;解析器从空格开始?

F# 为什么';t如果;直到;解析器从空格开始?,f#,parser-combinators,fparsec,F#,Parser Combinators,Fparsec,我尝试解析类似xml的标记(但不是正确的xml文档..): 我们的目标是只返回“凸缘宽度”,不带开头或尾随空格,而是带内部空格 open FParsec let testParser = pstring "<desc>" .>>. spaces >>. manyCharsTill anyChar (spaces .>>. pstring "</desc>") run testParser "<desc>

我尝试解析类似xml的标记(但不是正确的xml文档..): 我们的目标是只返回“凸缘宽度”,不带开头或尾随空格,而是带内部空格

open FParsec

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

run testParser "<desc> Flange width </desc>"
打开FParsec
让testParser=
pstring“>>。空间
>>. manyCharsTill anyChar(空格>.pstring“”)
运行testParser“法兰宽度”
如果我理解解析器组合符,那么预期结果是:

anyChar解析器继续吞咽字符的单元是“直到”解析器,它查找结尾标记后面的空格

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

输出:

val it : ParserResult<string,unit> =
  Failure:
Error in Ln: 1 Col: 15
<desc> Flange width </desc>
              ^
Expecting: '</desc>'
valit:ParserResult=
失败:
Ln:1列中的错误:15
凸缘宽度
^
应为:“”

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

问题是
空格
成功解析并将流移动到
w
的开头<代码>pstring“”然后失败

最终的结果是
endp
解析器失败,但它已经改变了状态(我们已经移动过了空格)。您希望解析器失败并且不更改状态(在空格之前)。相关文件(参见)对此进行了解释:

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

您可以使用以下命令来执行此操作:

解析器
p1.>>。?p2的行为与p1类似。p2
,但如果
p2
因非致命错误而失败且未更改解析器状态,即使
p1
更改了解析器状态,它也会返回到开始

因此,取而代之的是:

let testParser=
pstring“>>。空间
>>. manyCharsTill anyChar(空格>>?pstring“”)

请参阅一个有效的演示。

作为旁注,我还发现仅仅做
|>>有趣的(s:string)->s.Trim()
有时比跳过空白更容易,甚至更快。