JSONReader.js
/**
* 将json字符串转为token
*/
class JSONReader {
constructor(str) {
this.str = str;
this.pos = 0;
this.tokens = [];
this.scan();
}
scan() {
while(this.pos < this.str.length) {
let char = this.str[this.pos];
switch (char) {
case '[':
this.readArrayStart();
break;
case "{":
this.readObjectStart();
break;
case "\"":
this.readString();
break;
case ']':
this.readArrayEnd();
break;
case "}":
this.readObjectEnd();
break;
case ":":
this.readColon();
break;
case ",":
this.readComma();
break;
default:
this.readOther();
break;
}
}
}
/**
* 读取字符串,可能是对象的key,也可能是某个value
*/
readString() {
let str = '';
this.pos ++;
while(this.str[this.pos] !== '\"' && this.pos < this.str.length) {
str += this.str[this.pos];
this.pos ++;
}
this.pos ++;
this.tokens.push(['string',str]);
}
/**
* 读取冒号
*/
readColon() {
this.tokens.push(['colon',':']);
this.pos ++;
}
/**
* 读取数字类型
*/
readNumber() {
let numberStr = '';
while(/\d/.test(this.str[this.pos]) || this.str[this.pos] === '.') {
numberStr += this.str[this.pos];
this.pos ++;
}
this.tokens.push(['number',parseFloat(numberStr)]);
}
/**
* 读取布尔类型
* @param tailStr
*/
readBoolean(tailStr) {
if(tailStr.startsWith("true")) {
this.tokens.push(["boolean",true]);
this.pos += 4;
}else {
this.tokens.push(["boolean",false]);
this.pos += 5;
}
}
/**
* 读取null类型
*/
readNull() {
this.tokens.push(['null',null]);
this.pos += 4;
}
/**
* 读取对象开始符{
*/
readObjectStart() {
this.tokens.push(['objectStart','{']);
this.pos ++;
}
/**
* 读取数组开始符[
*/
readArrayStart() {
this.tokens.push(['arrayStart','[']);
this.pos ++;
}
readOther() {
let nextChar = this.str[this.pos];
let tailStr = this.str.substring(this.pos);
if(/\d/.test(nextChar)) {
this.readNumber();
}else if(tailStr.startsWith("null")) {
this.readNull();
}else if(tailStr.startsWith("true") || tailStr.startsWith("false")) {
this.readBoolean(tailStr);
}else if(/\s/.test(nextChar)) {
this.readBlank();
}else {
throw new Error("unexpected token")
}
}
/**
* 读取逗号
*/
readComma() {
this.tokens.push(['comma',',']);
this.pos ++;
}
/**
* 读取对象结束符
*/
readObjectEnd() {
this.tokens.push(['objectEnd','}']);
this.pos ++;
}
/**
* 读取数组结束符
*/
readArrayEnd() {
this.tokens.push(['arrayEnd',']']);
this.pos ++;
}
/**
* 读取空白符
*/
readBlank() {
while(/\s/.test(this.str[this.pos])) {
this.pos ++;
}
}
showTokens() {
this.tokens.forEach(item => {
console.log(item);
})
}
}
exports.JSONReader = JSONReader;
JSONParser.js
const {Stack} = require('../../Stack/Stack');
const {PlaceHolder} = require('./PlaceHolder')
/**
* 将token转为对象
*/
class JSONParser {
constructor(tokens) {
this.stack = new Stack();
this.tokens = tokens;
this.pos = 0;
this.result = null;
this.placeHolder = new PlaceHolder();
this.parse();
}
/**
* 解析
*/
parse() {
let tokenType = this.getNextToken(0);
switch (tokenType) {
case 'objectStart':
this.parseObject();
break;
case 'arrayStart':
this.parseArray();
break;
default:
this.result = this.getNextToken(1);
break;
}
}
/**
* 获取下一个token
* @param index token索引
* @returns {string|number}
*/
getNextToken(index) {
return this.tokens[this.pos][index];
}
/**
* 解析对象属性值
* @param object
*/
parseKeyValue(object) {
let key = this.getNextToken(1);
this.pos += 2;
if(this.getNextToken(0) === 'number' ||
this.getNextToken(0) ==='boolean' ||
this.getNextToken(0) === 'null' ||
this.getNextToken(0) === 'string'
) {
object[key] = this.getNextToken(1);
this.pos ++;
}else if(this.getNextToken(0) === 'objectStart') {
//value的位置暂时用占位符代替
object[key] = this.placeHolder;
//递归调用解析Object的方法
this.parseObject();
}else if(this.getNextToken(0) === 'arrayStart') {
object[key] = this.placeHolder;
this.parseArray();
}
}
/**
* 解析数组项
* @param arr
*/
parseArrayItem(arr) {
if(this.getNextToken(0) === 'number' ||
this.getNextToken(0) ==='boolean' ||
this.getNextToken(0) === 'null' ||
this.getNextToken(0) === 'string'
) {
arr.push(this.getNextToken(1));
this.pos ++;
}else if(this.getNextToken(0) === 'arrayStart') {
//value的位置暂时用占位符代替
arr.push(this.placeHolder);
//递归调用解析Object的方法
this.parseArray();
}else if(this.getNextToken(0) === 'objectStart') {
arr.push(this.placeHolder);
this.parseObject();
}
}
/**
* 解析数组
*/
parseArray() {
this.pos ++;
let arr = [];
this.stack.push(arr);
this.parseArrayItem(arr);
while(this.getNextToken(0) === 'comma') {
this.pos ++;
this.parseArrayItem(arr);
}
if(this.getNextToken(0) === 'arrayEnd') {
const current = this.stack.pop();
if(this.stack.isEmpty()) {
this.result = current;
}else {
//栈顶元素
const temp = this.stack.peek();
if(Array.isArray(temp)) {
for (let i = 0; i < temp.length; i++) {
if(temp[i] === this.placeHolder) {
temp[i] = current;
break;
}
}
}else {
const keys = Object.keys(temp);
//遍历栈顶Object的key
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
//找到占位符位置,并填充为当前对象
if(temp[key] === this.placeHolder) {
temp[key] = current;
break;
}
}
}
}
this.pos ++;
}
}
/**
* 解析对象
*/
parseObject() {
this.pos ++;
let object = {};
this.stack.push(object);
this.parseKeyValue(object);
//遇到逗号表示还有下一个键值对
while(this.getNextToken(0) === 'comma') {
//跳过逗号
this.pos ++;
//继续读取键值对
this.parseKeyValue(object);
}
//遇到对象结束符
if(this.getNextToken(0) === 'objectEnd') {
//弹出当前对象
const current = this.stack.pop();
if(this.stack.isEmpty()) {
//如果栈空了,表示结果收集完毕
this.result = current;
}else {
//栈顶元素
const temp = this.stack.peek();
const keys = Object.keys(temp);
//遍历栈顶Object的key
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
//找到占位符位置,并填充为当前对象
if(temp[key] === this.placeHolder) {
temp[key] = current;
break;
}
}
}
this.pos ++;
}
}
}
exports.JSONParser = JSONParser;
PlaceHolder.js
/**
* 占位符,空对象
*/
class PlaceHolder {
}
exports.PlaceHolder = PlaceHolder;
JSON.js
const {JSONReader} = require('./JSONReader');
const {JSONParser} = require('./JSONParser');
const {JSONFormat} = require('./JSONFormat');
class JSON {
static stringify(obj,replacer,space) {
const jsonFormat = new JSONFormat(obj,replacer,space);
return jsonFormat.stringify();
}
static parse(str) {
const jsonReader = new JSONReader(str);
const parser = new JSONParser(jsonReader.tokens);
return parser.result;
}
}
exports.JSON = JSON;
index.js
const {JSON} = require('./code/JSON');
const str = '[\n' +
'\t"a",\n' +
'\t"b",\n' +
'\t[\n' +
'\t\t"a",\n' +
'\t\t"b",\n' +
'\t\t[\n' +
'\t\t\t"a",\n' +
'\t\t\t"b",\n' +
'\t\t\t"c"\n' +
'\t\t]\n' +
'\t]\n' +
']';
console.log(JSON.parse(str));
执行结果
[ 'a', 'b', [ 'a', 'b', [ 'a', 'b', 'c' ] ] ]