如何检测FParsec解析器未完成全部输入解析的情况?
检测FParsec解析器是否未耗尽输入就停止的方法
这个问题很常见——FParsec的many这类组合子是贪婪但不强制耗尽输入的:它会尽可能解析匹配的合法片段,一旦遇到无法匹配的内容就立刻停止,并不会主动检查是否还有剩余输入未处理。要解决这个问题,核心是让解析器明确要求必须消耗完所有输入才能判定成功,这里有两种实用的方案:
方案一:强制耗尽输入(最直接的检测方式)
使用FParsec内置的eof组合子,它会要求解析器必须到达输入的末尾才能成功。把你的原解析器和eof组合起来,就能确保只有当所有输入都被合法解析时才返回Success。
修改后的代码如下:
let test p str = match run p str with | Success(result, _, _) -> printfn "Success: %A" result | Failure(errorMsg, s, _) -> printfn "Failure: %s %A" errorMsg s let str s = pstring s let a = str "a" .>> spaces let b = str "b" .>> spaces // 用 .>> eof 强制解析完所有输入 let p = many (a <|> b) .>> eof test p "ab a d bba " // 现在会返回 Failure: "预期输入结束,但找到了字符 'd'" (ErrorPosition { ... })
当输入中存在无法匹配的字符(比如示例里的'd'),解析器会在尝试匹配eof时失败,明确告诉你输入没有被完全解析;如果输入是完全合法的(比如"ab a bba "),则会正常返回Success。
方案二:获取已解析结果+剩余输入(灵活处理)
如果你不想直接让解析器失败,而是希望同时得到已解析的内容和未被处理的剩余输入,可以使用restOfInput组合子,它会返回当前位置到输入末尾的所有字符串:
let pWithRest = many (a <|> b) .>>. restOfInput test pWithRest "ab a d bba " // 会返回 Success: (["a"; "b"; "a"], "d bba ")
这样你可以自行判断剩余输入是否为空,从而确定是否存在未解析的内容。
内容的提问来源于stack exchange,提问作者Sean Kearon
相关产品推荐
相关产品推荐

