我刚刚开始学习解析,并且我在Haskell中编写了this simple parser(使用parsec)来读取JSON并为其构造一个简单的树。我在RFC 4627中使用语法。

但是,当我尝试解析字符串{"x":1 }时,我得到了输出:

解析错误(第1行,第8列):
意外的“}”
期待空格字符或“,”

仅当我在右大括号(])或mustachio(})前有空格时,才出现这种情况。

我做错了什么?如果我在结束符号前避免使用空格,则效果很好。

最佳答案

Parsec不会自动回绕和回溯。当您编写sepBy member valueSeparator时,valueSeparator会占用空白,因此解析器将按如下方式解析您的值:

{"x":1 }
[------- object
%        beginObject
 [-]     name
    %    nameSeparator
     %   jvalue
      [- valueSeparator
       X In valueSeparator: unexpected "}"

Legend:
[--]     full match
%        full char match
[--      incomplete match
X        incomplete char match


valueSeparator失败时,Parsec将不会返回并尝试不同的解析组合,因为valueSeparator中已经有一个字符匹配。

您有两种选择可以解决您的问题:


由于在JSON中空格是微不足道的,因此请始终在有效令牌之后而不是之前消耗空格。因此,tok仅应在char后面占用空白,因此其定义为tok c = char c *> ws(来自(*>)Control.Applicative);将相同的规则应用于所有其他解析器。由于您以这种方式输入“错误的解析器”之后再也不会占用空白空间,因此您最终不必回溯。
在Parsec中使用回溯功能,方法是在可能消耗多个字符的解析器之前添加try,如果解析器失败,则应回退其输入。


编辑:更新了ASCII图形,使其更具意义。

10-08 00:35