实现一个简单地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. leetcode 74 搜索二维矩阵 java

    题目: 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的最后一个整数. 示例 1: 输入: mat ...

  2. django视图缓存的实现

    django视图缓存的实现 1,安装 pip install django-redis setting.py CACHES = { "default":{ "BACKEN ...

  3. java实际项目中interface和abstract interface 区别

    参考:https://zhidao.baidu.com/question/424485344260391052.html 这2种有什么区别,根据实际项目经验 帮我解答下 谢谢啊~~~~~~~~~问题补 ...

  4. HDU 3007 模拟退火算法

    Buried memory Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  5. (二)SSO之CAS框架单点退出,自定义退出界面.

    用CAS的退出,只能使用它自己的那个退出界面,如果有这样的要求, 要求退出后自动跳转到登录界面, 该如何做呢?下面这篇文章实现了退出后可以自定义跳转界面.  用了CAS,发现退出真是个麻烦事,退出后跳 ...

  6. Linux 下的 netfilter 认识与常规操作

    Linux 下的 netfilter 认识与常规操作 前言 博客写到今天,1年7个月.可是包含所有写作经历,这个时间线可以达到三年. 上次更新了一篇 "镇站之宝" ,也是本站阅读量 ...

  7. TPS和QPS定义以及影响TPS的因素

    一.TPS:Transactions Per Second(每秒传输的事物处理个数),即服务器每秒处理的事务数.TPS包括一条消息入和一条消息出,加上一次用户数据库访问.(业务TPS = CAPS × ...

  8. 总结day5 ---- ,字典的学习,增删改查,以及字典的嵌套, 赋值运算

    内容大纲: 一:字典的定义 二:字典的增加 >1:按照key增加,  无则增加,有则覆盖 >2:setdefault()  ,无则增加,有则不变 三:字典的删除 >1:pop()  ...

  9. 功能一: 数据库访问DAO层方法定义

    功能1: 今天到现在为止 实战课程的访问量 yyyyMMdd courseID 使用数据库来进行存储我们的统计结果 Spark Streaming把统计结果写入到数据库里面 可视化前端根据: yyyy ...

  10. day4. python学习之字典

    字典和列表是最常用的数据类型,字典是一种key-value的数据类型,用{ }表示 1.字典的特性:无序的,没有下标 2.字典的使用:增删改查 info = { '20181101':"zh ...