我写的JSON解析器是不是递归的几种语言,但是到现在为止没有在JavaScript。它不是递归的,而是使用一个名为stack的本地数组。在actionscript中,这比递归速度快得多,内存效率也更高,并且我认为javascript会类似。
此实现仅对具有反斜杠转义的带引号的字符串使用eval
作为优化和简化。这可以很容易地用任何其他解析器的字符串处理来代替。转义处理代码很长,与递归无关。
此实现在(至少)以下方面不严格。它将8位字符视为空白。它允许在数字中引导“+”和“0”。它允许在数组和对象中跟踪“,”。它在第一个结果后忽略输入。所以“[+09,] 2”返回[9]并忽略“2”。
function parseJSON(inJSON) {
var result;
var parent;
var string;
var depth = 0;
var stack = new Array();
var state = 0;
var began , place = 0 , limit = inJSON.length;
var letter;
while (place < limit) {
letter = inJSON.charCodeAt(place++);
if (letter <= 0x20 || letter >= 0x7F) { // whitespace or control
} else if (letter === 0x22) { // " string
var slash = 0;
var plain = true;
began = place - 1;
while (place < limit) {
letter = inJSON.charCodeAt(place++);
if (slash !== 0) {
slash = 0;
} else if (letter === 0x5C) { // \ escape
slash = 1;
plain = false;
} else if (letter === 0x22) { // " string
if (plain) {
result = inJSON.substring(began + 1 , place - 1);
} else {
string = inJSON.substring(began , place);
result = eval(string); // eval to unescape
}
break;
}
}
} else if (letter === 0x7B) { // { object
stack[depth++] = state;
stack[depth++] = parent;
parent = new Object();
result = undefined;
state = letter;
} else if (letter === 0x7D) { // } object
if (state === 0x3A) {
parent[stack[--depth]] = result;
state = stack[--depth];
}
if (state === 0x7B) {
result = parent;
parent = stack[--depth];
state = stack[--depth];
} else {
// error got } expected state {
result = undefined;
break;
}
} else if (letter === 0x5B) { // [ array
stack[depth++] = state;
stack[depth++] = parent;
parent = new Array();
result = undefined;
state = letter;
} else if (letter === 0x5D) { // ] array
if (state === 0x5B) {
if (undefined !== result) parent.push(result);
result = parent;
parent = stack[--depth];
state = stack[--depth];
} else {
// error got ] expected state [
result = undefined;
break;
}
} else if (letter === 0x2C) { // , delimiter
if (undefined === result) {
// error got , expected previous value
break;
} else if (state === 0x3A) {
parent[stack[--depth]] = result;
state = stack[--depth];
result = undefined;
} else if (state === 0x5B) {
parent.push(result);
result = undefined;
} else {
// error got , expected state [ or :
result = undefined;
break;
}
} else if (letter === 0x3A) { // : assignment
if (state === 0x7B) {
// could verify result is string
stack[depth++] = state;
stack[depth++] = result;
state = letter;
result = undefined;
} else {
// error got : expected state {
result = undefined;
break;
}
} else {
if ((letter >= 0x30 && letter <= 0x39) || letter === 0x2B || letter === 0x2D || letter === 0x2E) {
var exponent = -2;
var real = (letter === 0x2E);
var digits = (letter >= 0x30 && letter <= 0x39) ? 1 : 0;
began = place - 1;
while (place < limit) {
letter = inJSON.charCodeAt(place++);
if (letter >= 0x30 && letter <= 0x39) { // digit
digits += 1;
} else if (letter === 0x2E) { // .
if (real) break;
else real = true;
} else if (letter === 0x45 || letter === 0x65) { // e E
if (exponent > began || 0 === digits) break;
else exponent = place - 1;
real = true;
} else if (letter === 0x2B || letter === 0x2D) { // + -
if (place != exponent + 2) break;
} else {
break;
}
}
place -= 1;
string = inJSON.substring(began , place);
if (0 === digits) break; // error expected digits
if (real) result = parseFloat(string);
else result = parseInt(string , 10);
} else if (letter === 0x6E && 'ull' === inJSON.substr(place , 3)) {
result = null;
place += 3;
} else if (letter === 0x74 && 'rue' === inJSON.substr(place , 3)) {
result = true;
place += 3;
} else if (letter === 0x66 && 'alse' === inJSON.substr(place , 4)) {
result = false;
place += 4;
} else {
// error unrecognized literal
result = undefined;
break;
}
}
if (0 === depth) break;
}
return result;
}
那么,递归编码与否,解析一个深度嵌套的结构必须经过相同的过程。你确定这个结构真的有效吗? “非常大”有多大? – Pointy 2010-08-24 14:44:21
这是合法的 - 它是一个包含几千个对象的数组。当它达到一定的大小时,eval()不能解析它(IE可以,但其他浏览器不能) – 2010-08-24 14:54:31
@Pointy yes它会经历相同的过程,但它不需要使用堆栈可能会耗尽空间。据推测,一个非递归的在堆中建立了一些其他等效的数据结构(希望它更大) – 2010-08-24 14:55:51