45fan.com - 路饭网

搜索: 您的位置主页 > 电脑频道 > 电脑教程 > 阅读资讯:开源Json解析器的浅述

开源Json解析器的浅述

2019-03-30 15:01:05 来源:www.45fan.com 【

之前在做项目中,Json 这种数据转换格式经常用,为什么呢?我认为是
1、它的易用性,跨平台性,它是JS(JavaScript)的子集,是一种对象字面量。
2、它与XML都是树结构的语法树;
同样的XML,JSON表示,Json则相对简洁,XML相对冗余,当然也是互相不可替代的,根据具体需求选择合适才是完美的。

做个原生的Json解析器是掌阅科技的大佬提出的一个问题,在之前没有相对的深入了解这个Json解析器,项目里用到的都是org.Json开源包\Gson包。这周就主要对Json解析器包括与塌相关的知识做个梳理,形成网络结构。想做Json解析器,必须对Json本身有了解,在这里主要点出几个下面需要用的点:
JSON结构:

"string":Java的String;
number:Java的Long或Double;
true/false:Java的Booleannull:Java的null;
[array]:Java的List<Object>或Object[];
{"key":"value"}:Java的Map<String, Object>。

JSON文法:

Jsonobject = {} | { members }
members = pair | pair , members
pair = string : value
array = [] | [ elements ]
elements = value | value , elements
value = string | number | object | array | true | false | null
string = “” | ” chars ”
chars = char | char chars
char = any-Unicode-character-except-“-or–or- control-character | \” | \ | \/ | \b | \f | \n | \r | \t | \u four-hex-digits
number = int | int frac | int exp | int frac exp
int = digit | digit1-9 digits | - digit | - digit1-9 digits
frac = . digits
exp = e digits
digits = digit | digit digits
e = e | e+ | e- | E | E+ | E-
细节可以参看《Json必知必会》http://download.csdn.net/download/qq_34417408/10122524

同时也要了解编译原理的一些知识:
编译过程:词法分析,语法分析,语义分析,当然其中还有代码优化,目标代码;
其中,
词法分析作用:找出单词 。如int a=b+c; 结果为: int,a,=,b,+,c和;
语法分析作用:找出表达式,程序段,语句等。如int a=b=c;的语法分析结果为int a=b+c这条语句。
语义分析作用:查看类型是否匹配等。

还有中间代码的优化:http://blog.csdn.net/qq_34417408/article/details/78126087(我之前总结的博客)

同时要了解解析器的功能,原理;
Json解析器是把输入字符串重新变成熟悉类型的对象,像一个函数,它的输入是一个表示JSON的字符串,输出是结构化的对应到语言本身的数据结构。

在解析过程中,主要有两部分一个是,词法分析,将源码解析为词法单元token;另一个是语法分析,构造语法树parser;当然都是基于Json 词法和文法。

在第一部分,形成词法分析时,即是构造自动机(DFA);在写Json之前,我先手写了几个简单的自动机,很久没写过,热了下身,其实只要逻辑分析没问题,是很简单的,就是代码实现。
(a|bb)一个可以有’a’和’b’的字符串,’b’出现时必为偶数个;

public class ABB {

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) throws Exception {
    // TODO code application logic here
    Scanner in =new Scanner(System.in);
    String string=in.nextLine();
    char[] ch=string.toCharArray();
    if(ch.length==0){
      throw new Exception("不合法字符!");
    }
    int i=0;
    while(i<ch.length){
      if(ch[i]=='a'){
        ++i;
      }else if(i<ch.length-1&&ch[i]=='b'){
        ++i;
        if(i<ch.length&&ch[i]=='b'){
          ++i;
        }else{
          throw new Exception("不合法字符!");
        }
      }else{
        throw new Exception("不合法字符!");
      }
    }
    System.out.println("合法字符!");
  }
}

由于Json 的结构特殊,在输入第一字符的时候就可以判断是哪个对象,{}/[]/string/true/false/number/null;我们可以加工构造并对应枚举类型即token流,进行词法分析:

STRING(字符串字面量)
NUMBER(数字字面量)
NULLnull)
START_ARRAY([)
END_ARRAY(])
START_OBJ({)
END_OBJ(})
COMMA(,)
COLON(:)
BOOLEAN(true或者false)
END_DOC(表示JSON数据的结束)

枚举类型:

public enum TokenType {
  START_OBJ, END_OBJ, START_ARRAY, END_ARRAY, NULL, NUMBER, STRING, BOOLEAN, COLON, COMMA, END_DOC
}

同时构造token类:

public class Token {
  private TokenType type;
  private String value;

  public Token(TokenType type, String value) {
    this.type = type;
    this.value = value;
  }

  public TokenType getType() {
    return type;
  }

  public void setType(TokenType type) {
    this.type = type;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

  public String toString() {
    return getValue();
  }
}

在进行Json解析的词法分析时,首先需要将字符串转为字符数组,我们可以用BufferReader(new StringReader(String str));
关于BufferReader()可以见:https://www.cnblogs.com/meilidelaohuhua/p/6638545.html ;
转化之后进行字符逐一分析,此时用到的是Json的结构的自动机,将其转化为token流。此时第一部分词法分析完成。
在第二部分语法树parser构造中,主要分两部分;
一块是对象Object文法,一块是数组Array文法,其他文法是基本类型;
其中对象可以用Map实现(Key:Value),数组用List集合

public class JObject implements Json {
  private Map<String, Value> map = new HashMap<>();
  public JObject(Map<String, Value> map) {
    this.map = map;
  }

  public int getInt(String key) {
    return Integer.parseInt((String) map.get(key).value());
  }

  public String getString(String key) {
    return (String) map.get(key).value();
  }

  public boolean getBoolean(String key) {
    return Boolean.parseBoolean((String) map.get(key).value());
  }

  public JArray getJArray(String key) {
    return (JArray) map.get(key).value();
  }

  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("{ ");
    int size = map.size();
    for (String key : map.keySet()) {
      sb.append(key + " : " + map.get(key));
      if (--size != 0) {
        sb.append(", ");
      }
    }
    sb.append(" }");
    return sb.toString();
  }
}
public class JArray implements Json, Value {
  private List<Json> list = new ArrayList<>();

  public JArray(List<Json> list) {
    this.list = list;
  }

  public int length() {
    return list.size();
  }

  public void add(Json element) {
    list.add(element);
  }

  public Json get(int i) {
    return list.get(i);
  }

  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("[ ");
    for (int i =0; i < list.size(); i++) {
      sb.append(list.get(i).toString());
      if (i != list.size() - 1) {
        sb.append(", ");
      }
    }
    sb.append(" ]");
    return sb.toString();
  }

  @Override
  public Object value() {
    return this;
  }
}

其中重要的是Json,和Value抽象类的建立得以使JObject和JArray相互转化,动态的完成对象和数组相互嵌套的转化。
另外,在构造token 类的时候把枚举类型和Value为属性,在后面添加list的时候,省了许多麻烦。
源码:https://github.com/weiyanyanyan/Json

资料查找:https://www.cnblogs.com/meilidelaohuhua/p/6638545.html
https://www.zhihu.com/question/24640264/answer/80500016
http://blog.csdn.net/yuanzhou314/article/details/43032067
https://www.liaoxuefeng.com/article/0014211269349633dda29ee3f29413c91fa65c372585f23000

 
 

本文地址:http://www.45fan.com/dnjc/99992.html
Tags: 解析 JSON 开源
编辑:路饭网
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部