关于解析器:自己动手写json解析器0x04生成对象

介绍通过分词和形象语法树生成后,咱们就能够依据语法树生成java对象,为了让程序尽量简略,object用Map返回,array用List<Map>返回,根本类型间接返回value 实现语法树到对象的生成绝对还是比较简单,首先咱们定义了一个总的入口函数 /** * 将json生成java对象 * * @param item * @return */public Object generate(Ast item) { if ("array".equals(item.getType())) { //返回数组对象 return generateList(item); } else if ("object".equals(item.getType())) { //返回object对象 return generateObject(item); } else if ("value".equals(item.getType())) { //根本类型json对象,比方"100"也是一个json对象 return item.getValue(); } return null;}对应三种类型的解决形式 generateObject /** * 生成object对象 * * @param astItem * @return */public Map generateObject(Ast astItem) { //object对象以Map模式返回 Map<String, Object> object = new HashMap<>(); for (Ast ast : astItem.getItems()) { Object value = null; if ("object".equals(ast.getType()) || "array".equals(ast.getType())) { value = generate(ast); } else if ("value".equals(ast.getType())) { value = ast.getValue(); } object.put(ast.getName(), value); } return object;}遍历object的字段如果是object或者array,那么通过入口函数进行递归如果是value间接取value值就行generateList ...

December 22, 2022 · 2 min · jiezi

关于解析器:自己动手写json解析器0x03抽象语法树

介绍后面两节咱们介绍了分词和分词荡涤,通过荡涤后的token列表曾经能够用来生产语法树,本节咱们将实现语法树的生成,语法树的目标就是将数据结构化,什么叫结构化,比方字符串表达式(1+(2*3))要写个程序计算这个后果还是有点难的,因为这个字符串只是一个字符串,咱们须要去解析,那么这个字符串就不是一个结构化的数据,如果给你的是解析后的数据,那么就很好解决,解析后的数据就是结构化的数据,你可能会说那不就是分词吗,其实不是的,也是以下面那个表达式为例,分词都是平铺构造,没有层级关系,但表达式有优先级,嵌套等层级关系,这个就是语法树要做的事。 实现难点生成语法树的难点在于,token数组是平铺构造,但语法树是树形构造,有层级关系,咱们须要将将平铺构造变成树形构造,当token数组中蕴含object和array时语法树就会有新的分支,因而重点就是要解决好object和array,这两个解决形式实质上是统一的,能够简化为找括号问题,什么意思呢,比方一个表达式(1+(2+(3+4)+5)+6)如何找到成对的括号,一种简略的办法是如果碰到(就进入递归,直到碰到)退出,这样最初一次递归会先匹配第一个)和咱们想要的后果相符,有点相似栈,后进先出,就以(1+(2+(3+4)+5)+6)为例,总共17个字符,括号的匹配状况应该是 0匹配163匹配136匹配10代码实现 public static void test(String text) { int begin = 0; int end = 0; while (index < text.length()) { int c = text.charAt(index); if (c == '(') { begin = index; char cc = text.charAt(++index); while (cc != ')') { test(text); cc = text.charAt(index); } end = index; System.out.println(String.format("%d匹配%d", begin, end)); } else if (c == ')') { break; } ++index; } }输入 6匹配103匹配130匹配16因为是最外面括号开始匹配所以先输入6匹配10,后果是合乎预期的,了解了这个就很容易了解语法树的生成过程 实现首先定义形象语法树数据结构,如下 public class Ast { //节点类型 private String type; //如果是object则是字段列表 //如果是array则是值列表 private List<Ast> items; //字段名(可为空) private String name; //字段值 private Object value; ....}语法树构建步骤如下 ...

December 22, 2022 · 2 min · jiezi

关于解析器:自己动手写json解析器0x02分词清洗

介绍在上一节中,咱们介绍了如何对json进行分词,并且胜利对示例json进行了分词,这一节咱们介绍如何对分词进行荡涤,可能荡涤这个词用的不是很精确,然而我也不晓得业余叫法叫啥,有晓得的同学心愿在评论区留言,分词荡涤的目标就是将tokens进行整顿,去掉一些没用的,而后进行一些整合便于后续的剖析,有点像大数据里的数据荡涤将脏数据荡涤为能被业务所用的高质量数据,所以这里用了分词荡涤这个词。 分词荡涤介绍为了便于前面步骤的解决,咱们这里须要对分词进行荡涤,荡涤后的分词列表能够满足以下要求 第一节中字符串都是当作type=string解决,通过荡涤后,能够辨别key和value如果实现了key-value的荡涤,那么kvSymbol就不须要了,后续也不须要用到这个token,能够从列表中移除实现以下是具体实现的代码 /** * token荡涤 * 辨别key和value的token * * @param originTokens 原始token列表 * @return 荡涤过的token列表 */public List<Token> tokenClean(List<Token> originTokens) { jsonTokens = new ArrayList<>(); int tokenIndex = 0; while (tokenIndex < originTokens.size()) { Token token = originTokens.get(tokenIndex); if ("string".equals(token.getType())) { if (tokenIndex + 1 < originTokens.size() && "kvSymbol".equals(originTokens.get(tokenIndex + 1).getType())) { token.setType("key"); jsonTokens.add(token); Token valueToken = originTokens.get(tokenIndex + 2); //object和array类型临时不设置value类型 if (!"object".equals(valueToken.getType()) && !"array".equals(valueToken.getType())) { valueToken.setType("value"); } jsonTokens.add(valueToken); //因为读取了kvSymbol和value两个token因而要+2 tokenIndex += 2; } else { //如果没有kvSymbol间接当作value进行解决 token.setType("value"); jsonTokens.add(token); } } else { //荡涤目前只解决string类型其余类型疏忽 jsonTokens.add(token); } ++tokenIndex; } return jsonTokens;}测试咱们应用示例json进行测试 ...

December 22, 2022 · 2 min · jiezi