有人可以指导如何编写一个可以获取JSON数据的类,并尝试将其解析为一个简单的缓冲列表,我们可以从中回读数据吗?
实施例。 JSON
{ name: 'John', age: 56 }
..将被解析为一个关键值对表
name John
age 56
如何编写一个有助于创建更快更简单的解析方法?
请不要建议任何现有的图书馆。提供解析JSON的概念。
答案 0 :(得分:22)
这个答案假设您真的想要编写一个解析器并准备投入所需的工作。
您必须从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.
“
“任何角色都可能被转义。如果角色在基本中 多语言平面(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。如果编写解析器的主要原因是学习如何操作,这可能是一个很好的起点。
如果您不允许(或不想)使用解析器生成器,则必须创建自己的解析器。这通常分为两部分:
lexer / tokenizer 。这可以识别语言规范中定义的基本原语。在这种情况下,它必须识别大括号,引号等。它可能还会构建数字的表示。
一个AbstractSyntaxTree (http://en.wikipedia.org/wiki/Abstract_syntax_tree,AST)生成器。在这里编写代码来汇编表示JSON抽象的树(例如,空格和curlies已被丢弃)。
当你拥有AST时,应该很容易迭代节点并创建所需的输出。
但编写解析器生成器,即使是像JSON这样的简单语言,也是很多工作。
答案 1 :(得分:6)
如果你的“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 :(得分:5)
使用表示JSON文本的字符串。
创建一个JsonToken类。我叫我的JToken。
查看步骤#1中的整个文本并解析出JToken。
以递归方式对您的JToken进行分组和嵌套。
尝试保持简单统一。所有JToken节点都有一个子数组,可以有0个或更多子节点。如果node是数组,则标记为数组。如果是OBJECT或ARRAY,子数组用于节点的子节点。唯一改变的是它被标记为的东西。还要将所有值保留为字符串类型。这样你只需要一个名为" value"的节点上的一个成员。在完成所有艰苦工作后,可以将其解释为正确的数据类型。
使用防御性编码和单元测试。编写解析器的所有组件的测试。最好再花3个小时以偏执的方式编写代码,假设你每秒都犯错,而不是花3个小时追捕错误。代码偏执不够,在调试时你很少会花时间沮丧。
示例代码: 当我在code-eval.com上做一个简单(具有讽刺意味)的挑战时。 有一个json菜单解析挑战。我以为这会是作弊 使用任何内置函数,因为对我来说代码挑战的重点 是测试你的算法问题解决能力。 挑战在于:https://www.codeeval.com/open_challenges/102/
My Code,它使用从头开始构建的解析器来传递此挑战 的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附带的标准解析器并不像我想要的那样解释信息,所以我正在编写自己的解析器。
答案 3 :(得分:0)
public abstract class AbstractMessageObject {
public String toString() {
Gson gson = new Gson();
//here mapping Object class name is prefixed to json message so otherwise knows the mapping object
return "^" + this.getClass().getName() + "^" + gson.toJson(this);
}
}
您可以通过扩展此AbstractMessageObject
来创建任何bean。每当您想要将该对象解析为json时,您只需要调用toString
方法
答案 4 :(得分:0)
我用Kotlin写了一个简单的解析器,它还不完整。但是,它可以作为您自己实施的起点。
感谢@ peter.murray.rust给出的想法,它也受h2database parser的启发。
它主要是逐个字符读取JSON字符串(使用StringReader),并尝试根据预期的JSON令牌进行解析。它实现了读取令牌,未读取char并最终将结果转换为AST的功能。
您可以在github上找到the code和test cases。