一个简单的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 & ...
随机推荐
- Message Loop 原理及应用
此文已由作者王荣涛授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Message loop,即消息循环,在不同系统或者机制下叫法也不尽相同,有被叫做event loop,也有 ...
- console使用技巧
http://heikezhi.com/yuanyi/10%E4%B8%AAchrome%20console%E5%AE%9E%E7%94%A8%E5%B0%8F%E6%8A%80%E5%B7%A7 ...
- [RHEL] RHEL7.0 下 Postfix + Dovecot 实现邮件发送
RHEL7.0 下 Postfix + Dovecot 实现邮件发送 一.前言 大家都对邮件服务(mail service)很感兴趣嘛.我在自己 博客站 预言了自己会实战一次,访问量一天到十几(毕竟平 ...
- [转]NSProxy实现AOP方便为ios应用实现异常处理策略
[转载自:http://blog.csdn.net/yanghua_kobe/article/details/8395535] 前段时间关注过objc实现的AOP,在GitHub找到了其中的两个库:A ...
- 3.3 PXC Strict Mode
摘要: 出处:黑洞中的奇点 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但请保留该 ...
- spring与shiro配置详解
1.加入shiro相关依赖的jar包 pom.xml部分内容如下: <dependency> <groupId>org.apache.shiro</groupId> ...
- Jupyter notebook用法
参考官网文档:https://jupyter-notebook.readthedocs.io/en/stable/public_server.html 0.介绍jupyter notebook (此前 ...
- (RaspBerry Pi) Python GPIO 基本操作
目前打算由潛入深慢慢學習RaspBerry Pi, 所以先由最容易下手的Python進入樹莓派的世界 首先要使用 GPIO 需要利用RPI.GPIO package想當然爾必須先安裝 所以先執行下列命 ...
- 并发编程>>并发级别(二)
理解并发 这是我在开发者头条看到的.@编程原理林振华 有目标的提升自己会事半功倍,前行的道路并不孤独. 1.阻塞 当一个线程进入临界区(公共资源区)后,其他线程必须在临界区外等待,待进去的线程执行完成 ...
- netty用户指南
Netty用户指南 一.前言 1.问题 当今世界我们需要使用通用的软件或库与其他组件进行通信,例如使用HTTP客户端从服务器中获取信息,或通过网络服务调用一个远程的方法.然而通用的协议及其实现通常不具 ...