JSON.parse方法实现

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' ] ] ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值