实现一个简单地json解析器。

两部分组成,词法分析、语法分析

词法分析

package com.mahuan.json;

import java.util.LinkedList;
import java.util.List; /**
* 词法分析
*/
public class Tokenizer {
// 待分析的字符串
private String json;
// 读取字符时的索引位置
private int index = 0; // 词法分析结果列表
private List<Token> tokens = new LinkedList<Token>();
// 获取词法分析结果时的索引位置
private int tokenIndex = 0; /**
* 构造函数,触发词法分析
* @param json
* @throws Exception
*/
public Tokenizer(String json) throws Exception {
this.json = json;
this.init();
} /**
* 读取字符串中的字符,索引位置加1
* @return
*/
private Character read() {
if (index < json.length())
return json.charAt(index++);
else
return null;
} /**
* 读取字符串中的字符,索引位置减1
*/
private void unread() {
index--;
} /**
* 进行词法分析
* @throws Exception
*/
private void init() throws Exception {
Token token = null;
while ((token = token()) != null) {
tokens.add(token);
}
} /**
* 按顺序读取字符串,获取词法分析结果
* @return
* @throws Exception
*/
private Token token() throws Exception {
Character c = read();
if (c == null)
return null;
// 忽略空白字符、换行符等
while (isSpace(c)) {
c = read();
}
if (isNull(c))
return new Token(TokenType.Null, null);
if (c == '{')
return new Token(TokenType.ObjectStart, "{");
if (c == '}')
return new Token(TokenType.ObjectEnd, "}");
if (c == '[')
return new Token(TokenType.ArrayStart, "[");
if (c == ']')
return new Token(TokenType.ArrayEnd, "]");
if (c == ',')
return new Token(TokenType.Comma, ",");
if (c == ':')
return new Token(TokenType.Colon, ":");
if (isTrue(c))
return new Token(TokenType.Boolean, "true");
if (isFalse(c))
return new Token(TokenType.Boolean, "false");
if (c == '"')
return new Token(TokenType.String, readString());
if (isNum(c)) {
unread();
return new Token(TokenType.Number, readNum());
}
throw new Exception("");
} /**
* 读取字符串
* @return
*/
private String readString() {
char c = read();
StringBuffer sb = new StringBuffer();
while (c != '"') {
sb.append(c);
if (isEscape(c)) {
c = read();
sb.append(c);
}
c = read();
}
return sb.toString();
} /**
* 读取数字,还未考虑所有数字表达形式
* @return
*/
private String readNum() {
char c = read();
StringBuffer sb = new StringBuffer();
while (c != '"' && c != ':' && c != ',' && c != ']' && c != '}') {
sb.append(c);
c = read();
}
unread();
return sb.toString();
} /**
* 判断是否为数字开头的特征
* @param c
* @return
*/
private boolean isNum(char c) {
if (c == '-' || ('0' <= c && c <= '9'))
return true;
return false;
} /**
* 判断是否为转义字符
* @param c
* @return
*/
private boolean isEscape(char c) {
if (c == '\\')
return true;
return false;
} /**
* 是否为true字符串
* @param c
* @return
* @throws Exception
*/
private boolean isTrue(char c) throws Exception {
if (c == 't') {
c = read();
if (c == 'r') {
c = read();
if (c == 'u') {
c = read();
if (c == 'e') {
return true;
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
return false;
}
} /**
* 是否为false字符串
* @param c
* @return
* @throws Exception
*/
private boolean isFalse(char c) throws Exception {
if (c == 'f') {
c = read();
if (c == 'a') {
c = read();
if (c == 'l') {
c = read();
if (c == 's') {
c = read();
if (c == 'e') {
return true;
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
return false;
}
} /**
* 是否为null字符串
* @param c
* @return
* @throws Exception
*/
private boolean isNull(char c) throws Exception {
if (c == 'n') {
c = read();
if (c == 'u') {
c = read();
if (c == 'l') {
c = read();
if (c == 'l') {
return true;
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
throw new Exception("Invalid JSON input.");
}
} else {
return false;
}
} /**
* 是否为空字符
* @param c
* @return
*/
private boolean isSpace(char c) {
if (c == '\t')
return true;
if (c == '\n')
return true;
if (c == '\r')
return true;
if (c == '\0')
return true;
if (c == ' ')
return true;
return false;
} /**
* 获取词法分析的下一个结果
* @return
*/
public Token next() {
if (tokenIndex + 1 < tokens.size())
return tokens.get(++tokenIndex);
return null;
} /**
* 获取当前位置的词法分析结果
* @return
*/
public Token get() {
if (tokenIndex < tokens.size())
return tokens.get(tokenIndex);
return null;
}
} /**
* 词法分析类型
*/
enum TokenType {
// object开始
ObjectStart,
// object结束
ObjectEnd,
// 数组开始
ArrayStart,
// 数组结束
ArrayEnd,
// 字符串
String,
// 数字
Number,
// boolean
Boolean,
// 空
Null,
// ,
Comma,
// :
Colon
} /**
* 词法分析单元
* @author mahuan
* @version 2017年12月13日
*/
class Token {
public TokenType type;
public String value; public Token(TokenType type, String value) {
this.type = type;
this.value = value;
}
}

语法分析

package com.mahuan.json;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; /**
* 语法分析
*/
public class Parser {
/**
* 分析Object,使用map数据结构标识
* @param tokenizer
* @return
* @throws Exception
*/
public static Map<String, Object> parserObject(Tokenizer tokenizer) throws Exception {
Map<String, Object> map = new HashMap<>();
Token token = null;
while (true) {
token = tokenizer.get();
if (token.type == TokenType.ObjectEnd)
break;
if (token.type == TokenType.ObjectStart) {
tokenizer.next();
continue;
}
if (token.type == TokenType.Comma) {
tokenizer.next();
continue;// 跳过,
}
String key = token.value;
token = tokenizer.next();
if (token.type != TokenType.Colon)
throw new Exception();
tokenizer.next();
map.put(key, parserValue(tokenizer));
}
return map;
} /**
* 分析Array,使用list数据结构标识
* @param tokenizer
* @return
* @throws Exception
*/
public static List<Object> parserArray(Tokenizer tokenizer) throws Exception {
List<Object> list = new LinkedList<>();
Token token = null;
while (true) {
token = tokenizer.get();
if (token.type == TokenType.ArrayEnd)
break;
if (token.type == TokenType.ArrayStart) {
tokenizer.next();
continue;
}
if (token.type == TokenType.Comma) {
tokenizer.next();
continue;
}
list.add(parserValue(tokenizer));
}
return list;
} /**
* 分析值,根据token再判断值的具体类型
* @param tokenizer
* @return
* @throws Exception
*/
public static Object parserValue(Tokenizer tokenizer) throws Exception {
Token token = tokenizer.get();
try {
if (token.type == TokenType.ObjectStart)
return parserObject(tokenizer);
else if (token.type == TokenType.ArrayStart)
return parserArray(tokenizer);
else if (token.type == TokenType.Boolean)
return Boolean.valueOf(token.value);
else if (token.type == TokenType.String)
return token.value;
else if (token.type == TokenType.Number)
return token.value;
else if (token.type == TokenType.Null)
return null;
throw new Exception("");
} finally {
// object和array分析完后,要跳过其end的token
// 其他类型分析完后,要跳过自身
tokenizer.next();
}
} }

测试代码

package com.mahuan.json;

public class Test {
public static void main(String[] args) throws Exception {
String json = "{ \"success\": true, \"message\": \"123\", \"result\": [ -2146464718]}";
Tokenizer tokenizer = new Tokenizer(json);
Object map = Parser.parserValue(tokenizer);
System.out.println(map);
}
}

一个简单的json解析器的更多相关文章

  1. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...

  2. 用c#自己实现一个简单的JSON解析器

    一.JSON格式介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着很多优点.例如易读性更好,占用空间更 ...

  3. 高手教您编写简单的JSON解析器

    编写JSON解析器是熟悉解析技术的最简单方法之一.格式非常简单.它是递归定义的,所以与解析Brainfuck相比,你会遇到轻微的挑战 ; 你可能已经使用JSON.除了最后一点之外,解析 Scheme的 ...

  4. kotlin 写的一个简单 sql 查询解析器

    package com.dx.efuwu.core import org.apache.commons.lang.StringUtils import java.sql.PreparedStateme ...

  5. 简单sql字段解析器实现参考

    用例:有一段sql语句,我们需要从中截取出所有字段部分,以便进行后续的类型推断,请给出此解析方法. 想来很简单吧,因为 sql 中的字段列表,使用方式有限,比如 a as b, a, a b... 1 ...

  6. 一起写一个JSON解析器

    [本篇博文会介绍JSON解析的原理与实现,并一步一步写出来一个简单但实用的JSON解析器,项目地址:SimpleJSON.希望通过这篇博文,能让我们以后与JSON打交道时更加得心应手.由于个人水平有限 ...

  7. 如何编写一个JSON解析器

    编写一个JSON解析器实际上就是一个函数,它的输入是一个表示JSON的字符串,输出是结构化的对应到语言本身的数据结构. 和XML相比,JSON本身结构非常简单,并且仅有几种数据类型,以Java为例,对 ...

  8. 几百行代码实现一个 JSON 解析器

    前言 之前在写 gscript时我就在想有没有利用编译原理实现一个更实际工具?毕竟真写一个语言的难度不低,并且也很难真的应用起来. 一次无意间看到有人提起 JSON 解析器,这类工具充斥着我们的日常开 ...

  9. C#字符串数组排序 C#排序算法大全 C#字符串比较方法 一个.NET通用JSON解析/构建类的实现(c#) C#处理Json文件 asp.net使用Jquery+iframe传值问题

    C#字符串数组排序   //排序只带字符的数组,不带数字的 private   string[]   aa   ={ "a ", "c ", "b & ...

随机推荐

  1. if、else if 、else及switch...case使用小记(C#)

    有时候编程编的久了,如果不停下来认真思考一下,即便是一些最基础的知识点,也可能让自己懵圈.其实,说到底还是打基础的时候没打牢,或者说自以为是地认为自己懂了,然后在打基础的时候就懒得思考懒得看了,结果就 ...

  2. windows 10 RelativePanel

    The new RelativePanel implements a style of layout that is defined by the relationships between its ...

  3. 抓取DUMP日志

    http://technet.microsoft.com/en-us/sysinternals/dd996900.aspx procdump -ma -c 60 -s 10 -n 3 <PID ...

  4. HBase – 探索HFile索引机制

    本文由  网易云发布. 作者: 范欣欣 本篇文章仅限内部分享,如需转载,请联系网易获取授权. 01 HFile索引结构解析 HFile中索引结构根据索引层级的不同分为两种:single-level和m ...

  5. iOS 获取 UITabViewController 和 UINavigationController 的图标位置

    这些图标是放在 UITabBar 和 UINavigationBar 里的.所以只要遍历它们的 subViews,找到类型是 UIButton 的就可以了. 所有想获取它们的相对位置很容易. 获取到相 ...

  6. IdHTTPServer使用注意问题

    如果在同一电脑上运行多个IdHTTPServer实例,IdHTTPServer使用时候,一定要注意“DefaultPort”属性,其实真正绑定端口是这个属性决定的,所以希望IdHTTPServer绑定 ...

  7. mysql主从报错截图

    1.首先确认报错的binlog和last event. 2.然后去主的机器上查看该报错的内容和报错的的位置,如果是结尾报错的,可以直接从新的binlog进行同步. #/mysql/logs# ../b ...

  8. python中多线程,多进程,多协程概念及编程上的应用

    1, 多线程 线程是进程的一个实体,是CPU进行调度的最小单位,他是比进程更小能独立运行的基本单位. 线程基本不拥有系统资源,只占用一点运行中的资源(如程序计数器,一组寄存器和栈),但是它可以与同属于 ...

  9. rpm 卸载

    卸载:python-urlgrabber-3.9.1-9.el6.noarch rpm -e python-urlgrabber-3.9.1-9.el6.noarch

  10. 找到windows中的环境变量

    我的电脑,右击--->属性---->高级系统设置---->高级----->环境变量