概述

附上完整的代码:

https://files.cnblogs.com/files/xcr1234/json.rar

一个类实现json解析核心代码(ObjectParser),其他的类都是工具类
(入口类是Json)

JSON:JavaScript 对象表示法(JavaScript Object Notation)。

JSON 是存储和交换文本信息的语法。类似 XML。

JSON 比 XML 更小、更快,更易解析。

在JSON中,分为6种对象:

  • 数字(整数或浮点数)
  • 字符串(在双引号中)
  • 逻辑值(true 或 false)
  • 数组(JsonArray)
  • 对象(JsonObject)
  • null

基本对象的实现

JsonObject其实就是一个HashMap,JsonArray其实就是一个ArrayList.

public class JsonObject extends HashMap<String,Object> {

}

public class JsonArray extends ArrayList<Object> {

}

JSON字符串的解析

以这个字符串为例:

{“success”:true,”id”:-10.5,”employees”:[{“firstName”:”Bill”,”lastName”:”Gates”},{“firstName”:”George”,”lastName”:”Bush”},{“firstName”:”Thomas”,”lastName”:”Carter”}]}

我们保证在只扫描一次整个的情况下,就将json结构解析成功。

传统的解析策略通常是通过词法分析,将json分为一个个的token,而这些token有着自己的类型和值;再通过语法分析构建一棵抽象语法树,进一步处理。比如""是一种,true/false又是一种。

其实根本不需要这么复杂。依我看来,json的token只有五种:true/false/null(归为一种,因为它们是固定值)、number、string、object、array。也不用特别在意start和end的Token区分,比如 { 符号和 } 符号。从一个 { 符号开始,到下一个它对应的 } 符号都是属于同一个json object的。这里的 { 与 } 、[ 与 ] 符号都是一一对应的。
我设计了一个nextObject()方法,它可以解析出json字符串中的下一个对象,然后在适当的时候装配即可。

nextObject方法的实现

提取字符

    public static boolean isSpace(char c){
return c == ' ' || c == '\r' || c == '\n';
} //方法得到当前字符,忽略空格、换行符
private char getChar(){
char c = json.charAt(pos);
while(isSpace(c)){
pos++;
c = getCurrentChar();
}
return c;
}

上面方法是消耗掉所有空白字符,直到读取到一个非空白字符,isSpace方法用于判断一个字符是否属于空白字符,pos表示当前指针指向的那个字符。也就是说,DFA从起始状态开始,若读到一个空字符,会在起始状态不断循环,直到遇到非空字符,状态转移情况如下:

解析

根据提取到的字符,转入不同的解析方法中,

例如字符是t,说明值可能是true,只需检查后面三个字符,如果是r、u、e,则可以直接返回true。

字符是f,说明值可能是false,只需检查后面四个字符,如果是a、l、s、e,则可以直接返回false。

碰到 \”,说明是字符串,在下一个\”出现之前,把扫描出来的字符都当成字符串中的字符,放到一个StringBuilder中去。

碰到 [ 符号,说明是数组了,就需要new一个JsonArray,在下一个 ] 符号出现之前,调用nextObject方法,把解析到的对象都放到这个JsonArray里面去。

碰到 { 符号,说明是JsonObject,就new一个JsonObject,这里每次需要连续调用两次nextObject,第一次结果作为key,第二次结果作为value。放到JsonObject中去。

解析boolean、null值

这类值的字符串只有固定的三种true、false、null,是最好解析的。在扫描到第一个字符为t、f、n时,只需检测后续字符是否符合固定值就可以了。checkChars方法实现了这个功能,chars是固定的序列,如果检测通过则返回true,否则返回false。

private boolean checkChars(char ...chars){
for(char ch : chars){
char c = getCurrentCharNext(); //得到当前字符,包括空格、换行符。将指针指向下一个字符
if(Character.toLowerCase(ch) != Character.toLowerCase(c)){
return false;
}
}
return true;
}

如果是true,就是`checkChars('t','r','u','e')`

解析数字

解析数字的实现是parseNumber方法,我们先new一个StringBuilder,向后扫描只要碰到0-9或者+-小数点,就添加到这个StringBuilder当中去,否则就StringBuilder.toString,将这个字符串转换成数字。

如果包含小数点,就用double,否则就用integer。

解析字符串

在json中字符串都是以双引号”开头,再以双引号”结尾的。当扫描到双引号”时,new一个StringBuilder,然后在下一个双引号”出现之前的每一个字符都需要添加到这个StringBuilder中去。需要注意的一点,字符串中是可能出现转义字符的。因此在扫描到一个字符为斜杠\时,需要取出下一个字符进行特殊处理。

解析JsonObject

连续调用两次nextObject,第一次结果作为key,第二次结果作为value。放到JsonObject中去。
注意逗号和冒号的处理。

JsonArray的解析

在下一个 ] 符号出现之前,递归调用nextObject方法,把解析到的对象都放到这个JsonArray里面去。

返回

由于nextObject只返回一个对象,我们用nextObject方法处理整个json字符串。那么nextObject方法就会得到你需要的JsonObject。

超大json对象的解析

参考 http://blog.csdn.net/dxiaolai/article/details/76359332

在大数据量的json场景下,不必将整个json字符串全部解析成json object后再处理,而是通过迭代器模式我们可以在解析字符串的同时使用对象。这样可以大大的提高程序的执行效率。

扩展ObjectParser类,使其成为一个迭代器,

public class ObjectParser implements Iterator<Object>{

    public Object next(){
return nextObject();
} public boolean hasNext(){
return pos < json.length();
} @Override
public void remove() { } }

这样就可以边解析边使用对象了。

ObjectParser parser = new ObjectParser ("json");
while(parser.hasNext()){
Object object = parser.next();
}

超大的json串,通常是以流的方式提供,我们不必要一次性将流字节全部读入内存,而是可以逐字符的解析。每次读取若干个字符,解析成对象;实现方式是使用BuffererReader,修改getChar等方法,每次读字符时从BuffererReader中读取。配合上面的迭代器模式,可考虑将一个BuffererReader封装成Iterator<Object>。

Json字符串解析原理、超大json对象的解析的更多相关文章

  1. js中Json字符串如何转成Json对象(4种转换方式)

    js中Json字符串如何转成Json对象(4种转换方式) 一.总结 一句话总结:原生方法(就是浏览器默认支持的方法) 浏览器支持的转换方式(Firefox,chrome,opera,safari,ie ...

  2. 使用DataContractJsonSerializer类将类型实例序列化为JSON字符串和反序列化为实例对象 分类: JSON 前端 2014-11-10 10:20 97人阅读 评论(1) 收藏

    一.JSON简介 JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换格式. JSON是"名值对"的集合.结构由大 ...

  3. DataTable转Json字符串(使用Newtonsoft.Json.dll)

    DataTable转Json字符串(使用Newtonsoft.Json.dll) 在需要把DataTable转为Json字符串时,自己手动拼接太麻烦,而且容易出错,费时费力,使用Newtonsoft. ...

  4. 使用 dynamic 标记解析JSON字符串 JDynamic :支持Json反序列化为Dynamic对象

    使用 dynamic 标记解析JSON字符串  http://www.cnblogs.com/taotaodetuer/p/4171327.html 1 string jsonStr = " ...

  5. Android开发中的Json字符串与复杂的嵌套对象互转。

    Gson 可能是大家都觉得比较简单吧.我发现用JSONObject和网上下载的JSONHelper类使用起来很无语,只能解析简单的单层对象,如果有嵌套的就不能直转转成可用对象了.所以网上找了一会儿,发 ...

  6. 将非常规Json字符串转换为常用的json对象

    如下所示,这是一个已经转换为Json对象的非常规Json字符串,原来是一个Json类型的字符串,在转换为Json对象时,查询资料发现有两种转换法,.parse()和.eval()方法,但是前辈们都极其 ...

  7. DataTable转json字符串,jQuery.parseJSON()把json字符串转为标准的json对象格式

    1.string res = DataTableToJson.DataTable2Json(dt);讲DataTable转换为json字符串 http://www.365mini.com/page/j ...

  8. Json对象与Json字符串的转化、JSON字符串与Java对象的转换

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

  9. Java读取Excel转换成JSON字符串进而转换成Java对象

    Jar包

  10. Json对象与Json字符串的转化、JSON字符串与Java对象的转换(转)

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

随机推荐

  1. js-异步机制与同步机制

    Javascript的优势之一是其如何处理异步代码.异步代码会被放入一个事件队列,等到所有其他代码执行后才进行,而不会阻塞线程 1 理解异步代码: 1.1 JavaScript最基础的异步函数是set ...

  2. 常用硬件设备GUID

    Class GUID Device Description CDROM 4D36E965-E325-11CE-BFC1-08002BE10318 CD/DVD/Blu-ray drives DiskD ...

  3. Python数据可视化利器Matplotlib,绘图入门篇,Pyplot介绍

    Pyplot matplotlib.pyplot是一个命令型函数集合,它可以让我们像使用MATLAB一样使用matplotlib.pyplot中的每一个函数都会对画布图像作出相应的改变,如创建画布.在 ...

  4. Android 屏幕相关概念(1)

    1.  术语和概念 术语 说明 备注  Screen size(屏幕尺寸)  指的是手机实际的物理尺寸,比如常用的2.8英寸,3.2英寸,3.5英寸,3.7英寸  摩托罗拉milestone手机是3. ...

  5. javascript 之基本包装类型--04

    基本包装类型 基本包装类型是特殊的引用类型.每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而可以调用属性.方法来进行后续操作. ECMAScript还提供了三种基本包装类型 ...

  6. 如何透彻分析Java开发人员

    第一部分:对于参加工作一年以内的同学.恭喜你,这个时候,你已经拥有了一份Java的工作. 这个阶段是你成长极快的阶段,而且你可能会经常加班.但是加班不代表你就可以松懈了,永远记得我说的那句话,从你入行 ...

  7. 深入理解Java虚拟机--下

    深入理解Java虚拟机--下 参考:https://www.zybuluo.com/jewes/note/57352 第10章 早期(编译期)优化 10.1 概述 Java语言的"编译期&q ...

  8. LeetCode 455. Assign Cookies (分发曲奇饼干)

    Assume you are an awesome parent and want to give your children some cookies. But, you should give e ...

  9. LeetCode 342. Power of Four (4的次方)

    Given an integer (signed 32 bits), write a function to check whether it is a power of 4. Example:Giv ...

  10. require.js实现js模块化编程(一)

    1.认识require.js: 官方文档:http://requirejs.org/RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的Requ ...