一个简单的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 & ...
随机推荐
- c#设计模式之装饰器模式(Decorator Pattern)
引子 在面向对象语言中,我们常常会听到这样一句话:组合优于继承.那么该如何去理解这句话呢? 下面我将以游戏装备为模型用简单的代码去展示它 先创建一个装备的抽象类,然后创建刀枪2个具体的业务子类 pub ...
- Android 获取模拟器与真机数据库
模拟器: localuser:~ localhost$ adb shell shell@android:/ $ su // 数据库复制到 Download 下 shell@android:/ # cp ...
- 【OCP-12c】CUUG 071题库考试原题及答案解析(23)
23.choose the best answer View the Exhibits and examine PRODUCTS and SALES tables. You issue the fol ...
- docker启动时报错
docker安装成功后,启动时报错. 1.后来排查后发现yum install docker安装的是从test存储库中安装的. 后来我指定了特定的版本后,而且从stable存储库安装的,以后再启动就好 ...
- robot framework-tags(标签)实例
robot framework的标签是一个简单而又强大的分类机制,功能如下: 标签在reports,logs以及测试数据中展示,显示关于测试用例的元数据信息 用例的执行统计(total,passed, ...
- USB-Redirector-Technician 永久破解版(USB设备映射软件)
USB-Redirector-Technician 这个软件对于搞安卓刷机的人想必非常熟悉,淘宝破解版售价:38 一个的东西 除了远程刷机,用于映射一些小型设备是没问题的,只要网跟得上~ USB-Re ...
- Java NIO学习与记录(四): SocketChannel与BIO服务器
SocketChannel与BIO服务器 SocketChannel可以创建连接TCP服务的客户端,用于为服务发送数据,SocketChannel的写操作和连接操作在非阻塞模式下不会发生阻塞,这篇文章 ...
- 思科 ISR路由器登录内置交换模块的方式
ISR2900/3900系列 登录:Router#service-module gigabitethernet1/0 session 退出: control+shift+6 x disconnect ...
- RHCE 共享文件系统
9.1 共享文件系统 概述: 共享文件系统通常有两种方式: 基于文件共享,一种直接共享文件夹给client端,常见的技术有NFS(Network File System )和 SMB (Server ...
- Web App、Hybrid App、 Native App
1.特点: 1. 偏交互的Native,偏浏览的Web:交互指复杂操作,输入/选择什么的2. 已稳定的Native,试错中的Web:H5页面用来做低成本验证很好3. 访问硬件Native,信息展示We ...