首页 > > > 撸一个 JSON 解析器
阅读本文大概需要 8 分钟。
来源:http://t.cn/EamWhIf
“名称/值”对的集合不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。 对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
{"姓名": "张三", "年龄": "18"}
值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。 数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。 值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
[
{
"姓名": "张三",
"年龄":"18"
},
{
"姓名": "里斯",
"年龄":"19"
}
]
{、 姓名、 :、 张三、 ,、 年龄、 :、 18、 }
package com.json.demo.tokenizer;
/**
BEGIN_OBJECT({)
END_OBJECT(})
BEGIN_ARRAY([)
END_ARRAY(])
NULL(null)
NUMBER(数字)
STRING(字符串)
BOOLEAN(true/false)
SEP_COLON(:)
SEP_COMMA(,)
END_DOCUMENT(表示JSON文档结束)
*/
public enum TokenType {
BEGIN_OBJECT(1),
END_OBJECT(2),
BEGIN_ARRAY(4),
END_ARRAY(8),
NULL(16),
NUMBER(32),
STRING(64),
BOOLEAN(128),
SEP_COLON(256),
SEP_COMMA(512),
END_DOCUMENT(1024);
private int code; // 每个类型的编号
TokenType(int code) {
this.code = code;
}
public int getTokenCode() {
return code;
}
}
package com.json.demo.tokenizer;
/**
* 存储对应类型的字面量
*/
public class Token {
private TokenType tokenType;
private String value;
public Token(TokenType tokenType, String value) {
this.tokenType = tokenType;
this.value = value;
}
public TokenType getTokenType() {
return tokenType;
}
public void setTokenType(TokenType tokenType) {
this.tokenType = tokenType;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "Token{" +
"tokenType=" + tokenType +
", value='" + value + '\'' +
'}';
}
}
package com.json.demo.tokenizer;
import java.io.IOException;
import java.io.Reader;
public class ReaderChar {
private static final int BUFFER_SIZE = 1024;
private Reader reader;
private char[] buffer;
private int index; // 下标
private int size;
public ReaderChar(Reader reader) {
this.reader = reader;
buffer = new char[BUFFER_SIZE];
}
/**
* 返回 pos 下标处的字符,并返回
* @return
*/
public char peek() {
if (index - 1 >= size) {
return (char) -1;
}
return buffer[Math.max(, index - 1)];
}
/**
* 返回 pos 下标处的字符,并将 pos + 1,最后返回字符
* @return
* @throws IOException
*/
public char next() throws IOException {
if (!hasMore()) {
return (char) -1;
}
return buffer[index++];
}
/**
* 下标回退
*/
public void back() {
index = Math.max(, --index);
}
/**
* 判断流是否结束
*/
public boolean hasMore() throws IOException {
if (index < size) {
return true;
}
fillBuffer();
return index < size;
}
/**
* 填充buffer数组
* @throws IOException
*/
void fillBuffer() throws IOException {
int n = reader.read(buffer);
if (n == -1) {
return;
}
index = ;
size = n;
}
}
package com.json.demo.tokenizer;
import java.util.ArrayList;
import java.util.List;
/**
* 存储词法解析所得的token流
*/
public class TokenList {
private List<Token> tokens = new ArrayList<Token>();
private int index = ;
public void add(Token token) {
tokens.add(token);
}
public Token peek() {
return index < tokens.size() ? tokens.get(index) : null;
}
public Token peekPrevious() {
return index - 1 < ? null : tokens.get(index - 2);
}
public Token next() {
return tokens.get(index++);
}
public boolean hasMore() {
return index < tokens.size();
}
@Override
public String toString() {
return "TokenList{" +
"tokens=" + tokens +
'}';
}
}
public TokenList getTokenStream(ReaderChar readerChar) throws IOException {
this.readerChar = readerChar;
tokenList = new TokenList();
// 词法解析,获取token流
tokenizer();
return tokenList;
}
/**
* 将JSON文件解析成token流
* @throws IOException
*/
private void tokenizer() throws IOException {
Token token;
do {
token = start();
tokenList.add(token);
} while (token.getTokenType() != TokenType.END_DOCUMENT);
}
/**
* 解析过程的具体实现方法
* @return
* @throws IOException
* @throws JsonParseException
*/
private Token start() throws IOException, JsonParseException {
char ch;
while (true){ //先读一个字符,若为空白符(ASCII码在[0, 20H]上)则接着读,直到刚读的字符非空白符
if (!readerChar.hasMore()) {
return new Token(TokenType.END_DOCUMENT, null);
}
ch = readerChar.next();
if (!isWhiteSpace(ch)) {
break;
}
}
switch (ch) {
case '{':
return new Token(TokenType.BEGIN_OBJECT, String.valueOf(ch));
case '}':
return new Token(TokenType.END_OBJECT, String.valueOf(ch));
case '[':
return new Token(TokenType.BEGIN_ARRAY, String.valueOf(ch));
case ']':
return new Token(TokenType.END_ARRAY, String.valueOf(ch));
case ',':
return new Token(TokenType.SEP_COMMA, String.valueOf(ch));
case ':':
return new Token(TokenType.SEP_COLON, String.valueOf(ch));
case 'n':
return readNull();
case 't':
case 'f':
return readBoolean();
case '"':
return readString();
case '-':
return readNumber();
}
if (isDigit(ch)) {
return readNumber();
}
throw new JsonParseException("Illegal character");
}
private Token readString() throws IOException {
StringBuilder sb = new StringBuilder();
while(true) {
char ch = readerChar.next();
if (ch == '\\') { // 处理转义字符
if (!isEscape()) {
throw new JsonParseException("Invalid escape character");
}
sb.append('\\');
ch = readerChar.peek();
sb.append(ch);
if (ch == 'u') { // 处理 Unicode 编码,形如 \u4e2d。且只支持 \u0000 ~ \uFFFF 范围内的编码
for (int i = ; i < 4; i++) {
ch = readerChar.next();
if (isHex(ch)) {
sb.append(ch);
} else {
throw new JsonParseException("Invalid character");
}
}
}
} else if (ch == '"') { // 碰到另一个双引号,则认为字符串解析结束,返回 Token
return new Token(TokenType.STRING, sb.toString());
} else if (ch == '\r' || ch == '\n') { // 传入的 JSON 字符串不允许换行
throw new JsonParseException("Invalid character");
} else {
sb.append(ch);
}
}
}
\"
\\
\b
\f
\n
\r
\t
\u four-hex-digits
\/
package com.json.demo.jsonstyle;
import com.json.demo.exception.JsonTypeException;
import com.json.demo.util.FormatUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* JSON的对象形式
* 对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
*/
public class JsonObject {
private Map<String, Object> map = new HashMap<String, Object>();
public void put(String key, Object value) {
map.put(key, value);
}
public Object get(String key) {
return map.get(key);
}
...
}
package com.json.demo.jsonstyle;
import com.json.demo.exception.JsonTypeException;
import com.json.demo.util.FormatUtil;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* JSON的数组形式
* 数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
*/
public class JsonArray {
private List list = new ArrayList();
public void add(Object obj) {
list.add(obj);
}
public Object get(int index) {
return list.get(index);
}
public int size() {
return list.size();
}
...
}


http://www.cnblogs.com/absfree/p/5502705.html
https://www.liaoxuefeng.com/article/0014211269349633dda29ee3f29413c91fa65c372585f23000?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
https://segmentfault.com/a/1190000010998941#articleHeader6
http://json.org/json-zh.html
<END>
推荐阅读:

微信扫描二维码,关注我的公众号
朕已阅 
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69902700/viewspace-3157679/ ,如需转载,请注明出处,否则将追究法律责任。