【问题标题】:How to write a basic JSON parsing class如何编写一个基本的 JSON 解析类
【发布时间】:2013-06-08 11:00:27
【问题描述】:

有人可以指导如何编写一个接收 JSON 数据的类,并尝试将其解析为一个简单的缓冲列表,我们可以从中读取数据吗?

例如。 JSON

{ name: 'John', age: 56 } 

..将被解析成键值对表

name John
age  56

如何编写有助于创建更快更简单的解析方法?

请不要推荐任何现有的库。提供解析 JSON 的概念。

【问题讨论】:

  • 你为什么不用Gson
  • 这不是有效的 JSON!
  • What have you tried 除了问我们吗?
  • “提前致谢,Samual krish” 那是 6 行噪音。以后别管了。为什么“没有 API”?似乎需要一个,并且有很好的 API 可用。
  • 为什么不使用任何现有的库?如果您不能使用现有的库,并且您没有足够的动力去查看该主题(和类似主题)的可用内容,那么它闻起来很像您想要为您完成的家庭作业。您期待完美的输入吗?

标签: java json parsing


【解决方案1】:

如果你的“JSON”真的是这样,你应该先拿一个棒球棒去敲它的生产者的头。认真的。

如果您真的坚持要编写自己的类(为什么?),例如,您可以使用这样的接口:

public interface MyParser
{
    boolean parse()
        throws MyParsingException;
    MyParser next();
}

然后,实现将采用CharBuffer 作为参数和地图构建器类;并解析你会这样做:

final CharBuffer buf = CharBuffer.wrap(yourSource);
final MyMapBuilder builder = new MyMapBuilder();

MyParser parser = new OpenBracketParser(buf, builder);

while (parser.parse())
    parser = parser.next();

// result is builer.build()

这只是一个例子……

第二种解决方案,您想使用现有的解析工具;在这种情况下,请查看Parboiled。由于您使用纯 Java 编写语法,因此比 antlr、jflex 或其他更容易使用。

最后,如果您认为足够了,并决定使用 JSON 库(您真的应该这样做),请使用 Jackson,它甚至可以读取格式错误的 JSON:

public static void main(final String... args)
    throws IOException
{
    final ObjectMapper mapper = new ObjectMapper()
        .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
        .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

    final JsonNode node = mapper.readTree("{name: 'John'}");
    System.out.println(node); // {"name":"John"}
}

【讨论】:

  • 他说没有图书馆。
【解决方案2】:

此答案假定您确实想编写一个解析器并准备投入所需的工作。

您必须从 JSON 的正式规范开始。我找到了http://www.ietf.org/rfc/rfc4627.txt。这精确地定义了语言。您必须实现规范中的所有内容并为其编写测试。您的解析器必须处理不正确的 JSON(如您的)并抛出异常。

如果您想编写解析器,请停下来思考,然后不要。让它正常工作需要做很多工作。无论你做什么,都要做好它 - 不完整的解析器是一种威胁,永远不应该分发。

您必须编写符合要求的代码。以下是规范中的一些短语。如果您不理解它们,则必须仔细研究并确保您理解:

"JSON 文本应以 Unicode 编码。默认编码为 UTF-8。”

"JSON 解析器必须接受所有符合 JSON 的文本 语法。”

"编码注意事项:如果是 UTF-8,则为 8 位;如果是 UTF-16 或 UTF-32,则为二进制

  JSON may be represented using UTF-8, UTF-16, or UTF-32.  When JSON
  is written in UTF-8, JSON is 8bit compatible.  When JSON is
  written in UTF-16 or UTF-32, the binary content-transfer-encoding
  must be used.

"

"任何字符都可以转义。如果该字符在 Basic
多语言平面(U+0000 到 U+FFFF),那么它可能是
表示为六个字符的序列:反向固线,后跟
由小写字母 u 后跟四个十六进制数字
对字符的代码点进行编码。虽然是十六进制字母 A
F 可以是大写或小写。因此,例如,包含
的字符串 只有一个反斜线字符可以表示为
“\u005C”。 "

如果你理解了这些并且仍然想编写一个解析器,那么检查一些其他的解析器,看看它们是否有一致性测试。为您自己的应用借用这些。

如果您仍然热衷于,您应该强烈考虑使用解析器生成器。例如 JAVACC、CUP 和我的首选工具 ANTLR。 ANTLR 非常强大,但可能很难开始。另请参阅我现在推荐的 Parboiled 的建议。 JSON 相对简单,这将是一个有用的练习。大多数解析器生成器生成一个完整的解析器,它可以创建可执行代码或生成 JSON 的解析树。

如果允许您查看的话,http://www.antlr.org/wiki/display/ANTLR3/JSON+Interpreter 有一个使用 ANTLR 的 JSON 解析器生成器。我也刚刚发现了一个Parboiled parser-generator for JSON。如果您编写解析器的主要原因是学习如何去做,那么这可能是一个很好的起点。

如果不允许(或不想)使用解析器生成器,那么您必须创建自己的解析器。这通常分为两部分:

词法分析器/标记器。这识别了语言规范中定义的基本原语。在这种情况下,它必须识别大括号、引号等。它可能还会构建数字表示。

A AbstractSyntaxTreehttp://en.wikipedia.org/wiki/Abstract_syntax_tree,AST)生成器。在这里,您编写代码来组装代表 JSON 抽象的树(例如,空格和花括号已被丢弃)。

当您拥有 AST 后,应该很容易迭代节点并创建所需的输出。

但是编写解析器生成器,即使是像 JSON 这样简单的语言,也是一项繁重的工作。

【讨论】:

  • ANTLR 的缺点是它使构建过程变得非常复杂。半熟就没有这个缺点了!可惜知名度不够。
  • @fge 同意。我去看看。
【解决方案3】:

我以前写过一篇。步骤:

  1. 取一个表示 JSON 文本的字符串。

  2. 创建一个 JsonToken 类。我叫我的 JToken。

  3. 从第 1 步开始遍历整个文本并解析出 JToken。

  4. 递归分组和嵌套您的 JToken。

  5. 尝试保持简单和统一。所有 JToken 节点都有一个可以有 0 个或多个子节点的子数组。如果节点是数组,则标记为数组。如果 is 是 OBJECT 或 ARRAY,则子数组用于节点的子节点。唯一改变的是它被标记为什么。还将所有值保留为字符串类型。这样,您只需要节点上的一个名为“value”的成员,在完成所有艰苦的工作后,它可以被解释为正确的数据类型。

  6. 使用防御性编码和单元测试。为解析器的所有组件编写测试。最好多花 3 个小时以偏执的方式编写代码,假设你每秒都在犯错误,而不是花 3 个小时寻找错误。代码偏执狂,你很少会在调试时感到沮丧。

示例代码: 当我在 code-eval.com 上做一个简单的(具有讽刺意味的)挑战时。 有一个 json 菜单解析挑战。我以为会作弊 使用任何内置函数,因为对我来说代码挑战的全部意义 是测试你的算法问题解决能力。 挑战就在这里:https://www.codeeval.com/open_challenges/102/

我的代码,通过这个挑战,使用从头开始构建的解析器 javascript:

CODE: https://pastebin.com/BReK9iij
Was not able to post it on stack-overflow because it is too much code.
Put it in a non-expiring paste-bin post.

注意:此代码可能需要一些改进。其中一些是非常低效的 它不适用于Unicode。

除非您以某种非标准方式解释 JSON,否则我不建议您编写自己的 JSON 解析器。

例如:我目前正在使用 JSONedit 来组织基于文本的分支 冒险。我只使用 JSON 文件格式,因为它很紧凑,而且查看器允许我扩展和收缩项目。 GOLang 附带的标准解析器不会按照我想要的方式解释信息,所以我正在编写自己的解析器。

【讨论】:

  • 非常有用,谢谢。缺少日期和时间支持是 JSON 的一个非常烦人的问题。我想添加像 <2018-11-07T09:39:12.345678Z> 这样的标记来表示根据 iso8601 的时间戳,这样浏览器端和服务器端都可以做更少的猜测工作,但除非我可以实现自己的 JSON 解析器,否则这是不可能的。
【解决方案4】:

我在 Kotlin 中编写了一个简单的解析器,它并不完整。但是,它可以作为您自己实施的起点。

感谢@peter.murray.rust 提供的想法,也受到h2database parser 的启发。

主要是逐个字符读取 JSON 字符串(使用 StringReader),并尝试根据预期的 JSON 令牌对其进行解析。它正在实现读取令牌,未读字符并最终将结果转换为AST的功能。

您可以在 github 上找到 the codetest cases

【讨论】:

    猜你喜欢
    • 2020-12-31
    • 1970-01-01
    • 2015-10-05
    • 2013-09-24
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多