2018年4月19日 星期四

js 仿製 php (serialize)






















module.exports = serialize;

function serialize(data) {
    let res = '';

    for (let i = 0, method; method = serialize.methods[i]; i++) {
        let temp;
        try {
            temp = method(data);
            res = temp;
            break;
        } catch (error) {
            if (error instanceof TypeError) {
                continue;
            } else {
                throw error;
            }
        }
    }
    return res;
}
//==============================================================================
(function (self) {

    self.methods = [
        function (data) {
            // string
            if (typeof data !== 'string') {
                throw new TypeError();
            }
            let res = 'String:' + String(data.length) + ':"' + data + '"';
            return res;
        },
        function (data) {
            // number
            if (typeof data !== 'number') {
                throw new TypeError();
            }
            let res = 'Number:' + data;
            return res;
        },
        function (data) {
            // undefined
            if (typeof data !== 'undefined') {
                throw new TypeError();
            }
            let res = 'undefined';
            return res;
        },
        function (data) {
            // null
            if (data !== null) {
                throw new TypeError();
            }
            let res = 'null';
            return res;
        },
        function (data) {
            // array
            if (!Array.isArray(data)) {
                throw new TypeError();
            }
            //----------------------------
            let res = 'Array:' + data.length + ':{';

            for (let i = 0; i < data.length; i++) {
                res += 'Number:' + i + ';';

                // 進入遞迴
                let _res = serialize(data[i]);

                res += _res + ';'
            }
            res += '}';

            return res;
        },
        //============================
        function (data) {
            // {}

            if (typeof data !== 'object' && data == null) {
                throw new TypeError();
            }
            let type = Object.prototype.toString.call(data);

            if (!/\[object Object\]/.test(data)) {
                throw new TypeError();
            }
            //----------------------------
            let length = Object.keys(data).length;
            let res = 'Object:' + length + ':{';

            for (let k in data) {
                if (data.hasOwnProperty(k)) {
                    // 進入遞迴
                    let _k = serialize(k);
                    let _res = serialize(data[k]);

                    res += _k + ';' + _res + ';';
                }
            }
            res += '}';

            return res;
        },
        //============================
        function (data) {
            // Map
            if (!(data instanceof Map)) {
                throw new TypeError();
            }

            let length = data.size;
            let res = 'Map:' + length + ':{';

            data.forEach(function (v, k) {
                // 進入遞迴
                k = serialize(k);
                v = serialize(v);

                res += (k + ';' + v + ';');
            });

            res += '}';

            return res;
        },
        function (data) {
            // 從函式實例化的物件
        }
    ];
})(serialize);
///////////////////////////////////////////////////////////////////////////////////////////
module.exports = unserialize;

function unserialize(data) {
    ++unserialize.count;
    //----------------------------
    let res;

    let objectType;

    data.replace(/^([^\:]+)/g, function (m, g) {
        objectType = g;
    });

    if (objectType in unserialize.methos) {
        res = unserialize.methos[objectType](data);
    } else {
        throw new Error(JSON.stringify(data) + ' no this method');
    }
    //----------------------------
    if (--unserialize.count === 0) {
        unserialize.jobs.length = 0;
    }

    return res;
}

(function (self) {
    self.UID = Math.floor(Math.random() * 0x10000000000).toString(16);

    self.count = 0;

    self.jobs = [];
    //==========================================================================
    // 從變數陣列中區分出 key, value
    self.getKeyValue = function (child_str) {

        // 避開 string 的影響
        // 清除所有 string 內部的內容,避免干擾發生
        child_str = self.prevProccessingString(child_str);
        // console.log(child_str);
        //----------------------------
        // 找尋屬於他的變數
        let str_variables = [];

        // 從左往右解
        while (child_str.length > 0) {
            let judge = 0;

            for (let i = 0; i < child_str.length; i++) {
                let char = child_str.charAt(i);

                if (char === '{') {
                    ++judge;
                }

                if (char === '}') {
                    --judge;
                }

                if ((char === ';' || i === (child_str.length - 1)) && judge === 0) {
                    // 取出一個區段
                    let target = child_str.slice(0, i + 1);
                    str_variables.push(target);
                    child_str = child_str.slice(i + 1);
                    break;
                }
            }
        }
        let res = {
            key: [],
            value: []
        };

        str_variables.forEach(function (v, i) {
            if (i % 2 === 0) {
                res.key.push(v);
            } else {
                res.value.push(v);
            }
        });

        return res;
    };
    //==========================================================================
    self.checkString = function (str) {


        let reg = new RegExp('@_' + unserialize.UID + '_(\\d+)_@');

        while (reg.test(str)) {
            res = reg.exec(str);
            let i = Number(res[1]);

            if (typeof unserialize.jobs[i] !== 'undefined') {
                let s = unserialize.jobs[i];
                str = str.replace(reg, s);

            } else {
                throw new Error('no find match string recorder');
            }
        }
        return str;
    };
    //==========================================================================
    // 這邊要加強
    // 對 unicode......等的加強
    self.prevProccessingString = function (str) {

        let res, reg = /String:(\d+):"/g;
        let positionList = [];

        while (res = reg.exec(str)) {
            // 匹配的字數
            let i = res[0].length;

            // 匹配的位置
            let index = res.index;

            // 文字的長度
            let length = parseInt(res[1], 10);

            if (length === 0) {
                // 沒有內容就不需處理
                continue;
            }

            let data = {
                s: (index + i),
                e: (index + i + length - 1)
            };

            data.target = str.slice(data.s, data.e + 1);

            positionList.unshift(data);
            // console.log(res);
        }

        positionList.forEach(function (d) {
            let start = d.s;
            let end = d.e;

            let index = unserialize.jobs.length;
            let replace = '@_' + unserialize.UID + '_' + index + '_@';


            let head = str.slice(0, start);
            let foot = str.slice(end + 1);
            let middle = str.slice(start, end + 1);

            unserialize.jobs[index] = middle;

            str = head + replace + foot;
        });

        return str;
    };
    //==========================================================================
    self.methos = {
        String: function (data) {
            let res = /"(.*)"/.exec(data);
            return res[1];
        },
        //======================================
        Number: function (data) {
            let res = /Number:(\d*)/.exec(data);
            return Number(res[1]);
        },
        //======================================
        Object: function (data) {
            let res = {};

            // 物件本身的描述
            let self_str = '';
            // 孩子的描述
            let child_str;
            let keyLength = 0;

            data.replace(/^([^\{\}]+?)\{(.*)\}/g, function (m, g1, g2) {
                self_str = g1;
                child_str = (g2 == null ? '' : g2);
                return '';
            });
            //----------------------------

            self_str.replace(/^[^:\d]+:(\d+):/g, function (m, g1) {
                keyLength = Number(g1);
            });
            //----------------------------           
            let d = self.getKeyValue(child_str);

            let keyList = d.key;
            let valueList = d.value;

            // 變數長度檢查
            if (keyLength !== keyList.length || keyList.length !== valueList.length) {
                throw new Error(data + ' variable length have trouble');
            }
            //----------------------------
            keyList.forEach(function (k, i) {
                console.dir(data);

                let v = valueList[i];
                k = unserialize.checkString(k);
                v = unserialize.checkString(v);

                // 遞迴
                k = unserialize(k);
                v = unserialize(v);

                res[k] = v;
            });

            //----------------------------
            if (keyLength !== Object.keys(res).length) {
                throw new Error("analyze error(" + data + ")");
            }
            return res;
        },
        //======================================
        Map: function (data) {
            let res = new Map();

            // 物件本身的描述
            let self_str = '';
            // 孩子的描述
            let child_str;
            let keyLength = 0;

            data.replace(/^([^\{\}]+?)\{(.*)\}/g, function (m, g1, g2) {
                self_str = g1;
                child_str = (g2 == null ? '' : g2);
                return '';
            });
            //----------------------------

            self_str.replace(/^[^:\d]+:(\d+):/g, function (m, g1) {
                keyLength = Number(g1);
            });
            //----------------------------           
            let d = self.getKeyValue(child_str);

            // console.dir(d);

            let keyList = d.key;
            let valueList = d.value;

            // 變數長度檢查
            if (keyLength !== keyList.length || keyList.length !== valueList.length) {
                throw new Error(data + ' variable length have trouble');
            }

            keyList.forEach(function (k, i) {
                let v = valueList[i];

                k = unserialize.checkString(k);
                v = unserialize.checkString(v);

                // 遞迴
                k = unserialize(k);
                v = unserialize(v);

                res.set(k, v);
            });
            //----------------------------
            return res;
        },
        Array: function (data) {
            let res = [];

            // 物件本身的描述
            let self_str = '';
            // 孩子的描述
            let child_str;
            let keyLength = 0;

            data.replace(/^([^\{\}]+?)\{(.*)\}/g, function (m, g1, g2) {
                self_str = g1;
                child_str = (g2 == null ? '' : g2);
                return '';
            });
            //----------------------------

            self_str.replace(/^[^:\d]+:(\d+):/g, function (m, g1) {
                keyLength = Number(g1);
            });
            //----------------------------           
            let d = self.getKeyValue(child_str);

            // console.dir(d);

            let keyList = d.key;
            let valueList = d.value;

            // 變數長度檢查
            if (keyLength !== keyList.length || keyList.length !== valueList.length) {
                throw new Error(data + ' variable length have trouble');
            }

            keyList.forEach(function (k, i) {
                let v = valueList[i];

                k = unserialize.checkString(k);
                v = unserialize.checkString(v);

                // 遞迴
                k = unserialize(k);
                v = unserialize(v);

                res[k] = v;
            });
            //----------------------------
            return res;
        },
        O: function (data) {
            // 非預設物件
            // 從函式實例化的物件
        },
    }
})(unserialize);