修复错误的JSON语法

时间:2012-01-02 06:32:56

标签: json parsing haskell parsec

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

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

parse error at (line 1, column 8):
unexpected "}"
expecting whitespace character or ","

当我在结束括号(])或mustachio(})之前有空格时,似乎只会发生这种情况。

我做错了什么?如果我在结束符号之前避免使用空格,那么它就能完美运行。

2 个答案:

答案 0 :(得分:6)

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中匹配。

您有两种方法可以解决您的问题:

  1. 由于JSON中的空白空间无关紧要,因此在重要令牌之后始终消耗空白,从未使用过。因此,tok应仅在char后使用空格,因此其定义为tok c = char c *> ws(来自(*>)的{​​{1}});将相同的规则应用于所有其他解析器。因为在以这种方式进入“错误的解析器”之后你永远不会消耗空白,所以你最终不必回溯。
  2. 通过在可能消耗多个字符的解析器前添加Control.Applicative,在Parsec中使用反向跟踪,如果失败则应回滚它们的输入。
  3. 编辑:更新了ASCII图形以使其更有意义。

答案 1 :(得分:1)

一般解决方案是让所有解析器跳过尾随空格。查看Parsec文档中的lexeme(在ParsecToken中)以获得一个简洁的方法,或者自己制作一个简单的版本:

 lexeme parser = do result <- parser
                    spaces
                    return result

然后在所有标记上使用此函数(如数字文字)。这样,您只需要担心表达式开头的空格。

有关ParsecToken和朋友的详细信息,请查看Parsec docs的“词法分析”部分。

只有在令牌之后才跳过空白才有意义,除非在最开始你可以手动跳过它。即使您最终没有使用ParsecToken模块,也应该采用这种方法。

您似乎已经tok的行为与我的lexeme相似,只是它消耗了两个方面的空白。将其更改为仅在令牌之后消耗空白,并在手动输入的最开头忽略空格。这应该(理想情况:) :)解决问题。