手写 JSON 解析器
手写 JSON 解析器
实现原理
- 理解JSON的语法,可以使用 https://www.json.cn/ 。按照 json 规范,除了对象,输入 Array、Boolean、Number、Undefined 都是可以的。
绘制「对象」有限状态机:
- 说明:先不用考虑状态机整体,先考虑最常用的对象输入
- 对象状态机流程:
- 首先判断 { 字符
- 紧接着判断空白字符,判断其后是否为 }
- 如果是,则结束
- 如果不是,则解析 字符串 作为 key, 解析 空白字符,解析 : ,解析 value 的值。
- 因为可以有多个 key value 对,所以继续解析 , 然后重复上一步
代码实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* 解析对象
* @returns {object}
*/
function parseObject() {
if (str[idx] === '{') {
++idx;
skipWhiteSpace(); // 跳过空白字符
const res = {};
let init = true;
while (str[idx] !== '}') { // 循环匹配,找到多个 key-value
if (!init) { // 如果不是第一个key-value,应该匹配 ,
skipWhiteSpace();
eatComma();
skipWhiteSpace();
}
init = false;
const key = parseString(); // 解析 key
skipWhiteSpace();
eatColon(); // 匹配 :
skipWhiteSpace();
const value = parseValue(); // 解析 value
res[key] = value;
}
++idx;
return res;
}
}
/**
* 解析值
* @returns {any}
*/
function parseValue() {
skipWhiteSpace(); // 跳过空白字符
// 这里就是把 value 当作 string / number / object / array 等进行尝试匹配
// 如果匹配成功,指针idx会移动,并且能拿到 val
const val = parseString() ?? parseNumber() ?? parseObject() ?? parseArray() ??
parseKeyword("true", true) ?? parseKeyword("false", false) ?? parseKeyword("null", null) ?? parseKeyword("undefined", undefined);
skipWhiteSpace(); // 跳过空白字符
return val;
}
代码实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 解析数组
* @returns {any[]}
*/
function parseArray() {
if (str[idx] === "[") {
++idx;
skipWhiteSpace();
const res = []
let init = true;
while (str[idx] !== ']') {
if (!init) {
skipWhiteSpace();
eatComma();
skipWhiteSpace();
}
init = false;
const value = parseValue();
res.push(value);
}
++idx;
return res;
}
}
- 依次绘制「其它数据类型」有限状态机,直接看代码即可,这里不重复了。其中比较麻烦的是 Number 。
最终,由于前面提到的JSON规范,对象、Array数组等都可以直接作为Input进行解析,所以函数返回就是
parseValue调用,而不是parseObject。1 2 3 4 5 6 7 8 9 10
/** * @description 解析json * @author dongyuanxin * @param {string} str */ function parseJson(str) { let idx = 0; return parseValue(str); // ... 各种parse定义 }
使用效果
源码地址
根据文章,自己也实现了一份JSON解析器代码。
参考链接
本文由作者按照 CC BY 4.0 进行授权


