const rx_one = /^[],:{}s]*$/;
const rx_two = /\(?:["\/bfnrt]|u[0-9a-fA-F]{4})/g;
// 匹配合法json符号
// "asd" or 1.23 or 1.3e4 or 1.3e-4 or 1.3e+4 or -10 之类的
const rx_three = /"[^"\
]*"|true|false|null|-?d+(?:.d*)?(?:[eE][+-]?d+)?/g;
// :[
// ,[
const rx_four = /(?:^|:|,)(?:s*[)+/g;
// 一些符号的unicode表示法
const rx_dangerous = /[u0000u00adu0600-u0604u070fu17b4u17b5u200c-u200fu2028-u202fu2060-u206fufeffufff0-uffff]/g;
export function jsonParse(text: string, reviver?: Function): any {
// 接受一个文本和一个可选的reviver函数,然后返回
// 如果文本是有效的JSON文本,则为JavaScript值
let j;
function walk(holder: any, key: any) {
// walk方法用于递归遍历结果结构,因此可以进行修改。
let k: string | number;
let v: any;
let value = holder[key];
if (value && typeof value === "object") {
// {} or []
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
return reviver?.call(holder, key, value);
}
}
// 解析分为四个阶段。 在第一阶段,我们替换某些
// 具有转义序列的Unicode字符。 JavaScript处理许多字符
// 错误地将其静默删除,或将其视为行尾。
text = String(text);
rx_dangerous.lastIndex = 0;
if (rx_dangerous.test(text)) {
// 转义序列的Unicode字符
text = text.replace(rx_dangerous, function(match) {
return "\u" + ("0000" + match.charCodeAt(0).toString(16)).slice(-4);
});
}
// 在第二阶段,我们针对看起来像正则表达式的文本
// 用于非JSON模式。 我们特别关注"()"和"new"
// 因为它们会引起调用,而"="则可能导致突变
// 但是为了安全起见,我们要拒绝所有意外的形式。
// 为了解决此问题,我们将第二阶段分为4个正则表达式操作
// 严重影响IE和Safari的regexp引擎的效率低下。 首先我们
// 将JSON反斜杠对替换为"@"(非JSON字符)。 第二,我们
// 用"]"字符替换所有简单值标记。 第三,我们删除所有
// 用冒号或逗号或文本开头的方括号。 最后,
// 我们希望看到其余字符只是空格或"]"或
// "."或":"或"{"或"}". 如果是这样,那么该文本对于eval是安全的。
if (
rx_one.test(
/*`{"name": "ajanuw"}` => `{]: ]}` */
text
.replace(rx_two, "@")
.replace(rx_three, "]")
.replace(rx_four, "")
)
) {
// 在第三阶段,我们使用eval函数将文本编译为
// JavaScript结构。 "{"运算符存在句法歧义
// 在JavaScript中:它可以开始一个块或一个对象文字。 我们包装文字
// 尽可能消除歧义
j = eval(`(${text})`);
// 在可选的第四阶段,我们递归遍历新结构,
// 每个名称/值对到reviver函数进行可能的转换
return typeof reviver === "function"
? walk(
{
"": j
},
""
)
: j;
}
// 如果文本不是JSON可解析的,则抛出SyntaxError。
throw new SyntaxError("json parse error!!");
}
const r = jsonParse(`{"name": "ajanuw"}`);
console.log({ result: r });