一个简单的json解析器
实现一个简单地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解析器的更多相关文章
- 自己动手实现一个简单的JSON解析器
1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...
- 用c#自己实现一个简单的JSON解析器
一.JSON格式介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着很多优点.例如易读性更好,占用空间更 ...
- 高手教您编写简单的JSON解析器
编写JSON解析器是熟悉解析技术的最简单方法之一.格式非常简单.它是递归定义的,所以与解析Brainfuck相比,你会遇到轻微的挑战 ; 你可能已经使用JSON.除了最后一点之外,解析 Scheme的 ...
- kotlin 写的一个简单 sql 查询解析器
package com.dx.efuwu.core import org.apache.commons.lang.StringUtils import java.sql.PreparedStateme ...
- 简单sql字段解析器实现参考
用例:有一段sql语句,我们需要从中截取出所有字段部分,以便进行后续的类型推断,请给出此解析方法. 想来很简单吧,因为 sql 中的字段列表,使用方式有限,比如 a as b, a, a b... 1 ...
- 一起写一个JSON解析器
[本篇博文会介绍JSON解析的原理与实现,并一步一步写出来一个简单但实用的JSON解析器,项目地址:SimpleJSON.希望通过这篇博文,能让我们以后与JSON打交道时更加得心应手.由于个人水平有限 ...
- 如何编写一个JSON解析器
编写一个JSON解析器实际上就是一个函数,它的输入是一个表示JSON的字符串,输出是结构化的对应到语言本身的数据结构. 和XML相比,JSON本身结构非常简单,并且仅有几种数据类型,以Java为例,对 ...
- 几百行代码实现一个 JSON 解析器
前言 之前在写 gscript时我就在想有没有利用编译原理实现一个更实际工具?毕竟真写一个语言的难度不低,并且也很难真的应用起来. 一次无意间看到有人提起 JSON 解析器,这类工具充斥着我们的日常开 ...
- C#字符串数组排序 C#排序算法大全 C#字符串比较方法 一个.NET通用JSON解析/构建类的实现(c#) C#处理Json文件 asp.net使用Jquery+iframe传值问题
C#字符串数组排序 //排序只带字符的数组,不带数字的 private string[] aa ={ "a ", "c ", "b & ...
随机推荐
- NIO-直接内存
写NIO程序经常使用ByteBuffer来读取或者写入数据,那么使用ByteBuffer.allocate(capability)还是使用ByteBuffer.allocteDirect(capabi ...
- Android中Textview显示Html,图文混排,支持图片点击放大
本文首发于网易云社区 对于呈现Html文本来说,Android提供的Webview控件可以得到很好的效果,但使用Webview控件的弊端是效率相对比较低,对于呈现简单的html文本的话,杀鸡不必使用牛 ...
- 使用Anaconda的python安装虚拟环境是出现错误:python -m venv venvdir----Error: Command '['D:\\Development\\Django\\test\\Scripts\\python.exe', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit
在创建python虚拟环境的时候,如果使用的是Anaconda中集成的python -m venv venvdir就会出现不能安装pip的错误,原因是Anaconda没有ensurepip, 解决办法 ...
- 微信小程序获取当前经纬度并逆解析地址代码
功能如标题. map.wxml代码如下: <!--miniprogram/pages/map/map.wxml--> <view><text>经度{{jd}}< ...
- Maven的Mirror和Repository 的详细讲解
1 Repository(仓库) 1.1 Maven仓库主要有2种: remote repository:相当于公共的仓库,大家都能访问到,一般可以用URL的形式访问 local repository ...
- 深度解析CNN
[1]Deep learning简介 [2]Deep Learning训练过程 [3]Deep Learning模型之:CNN卷积神经网络推导和实现 [4]Deep Learning模型之:CNN的反 ...
- iOS --高仿QQ空间页面
1.首先分析一下qq空间页面的主要2个功能: 1)随着TableView的向上滑动导航栏的颜色渐变,变化过程是从透明变成白色. 2)随着TableView的向下滑动,图片随着offset放大. 2.首 ...
- 禅道与bugfree区别
bugfree更偏重bug管理, 禅道是以项目管理为目标, 所以出发点不一样. 我们bug追踪管理使用bugfree,项目管理计划使用禅道,配置管理使用svn bugfree很low,安装需要环境特别 ...
- java并行之parallelStream与CompletableFuture比较
1. import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; im ...
- 如何给oneindex网盘增加评论、密码查看、read me,头提示功能。
来自我的博客:www.resource143.com 微信公众号:资源库resource 视频教程地址 点击查看 评论功能 特性 使用 GitHub 登录 支持多语言 [en, zh-CN, zh-T ...