我有一个非常大的JSON字符串,我需要使用浏览器中的JavaScript进行解析。现在,在一些浏览器中,我的堆栈空间不足。不幸的是,我的JSON可以包含用户字符串,所以我不能使用eval或者让浏览器解析它。
我查看了一些标准的JavaScript JSON解析器,它们是递归的。想知道是否有人知道任何安全且非递归的JSON解析器。我愿意让它拥有更少的功能 - 我只有一大堆物体。
或者,如果有人知道一个可能很容易修改的内容,那也将是一个很大的帮助。
编辑:仔细检查一下,解析器内部使用的eval()会抛出堆栈溢出。所以,它必须是递归的。
答案 0 :(得分:5)
答案 1 :(得分:3)
我编写的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;
}
答案 2 :(得分:1)
我建议你将JSON字符串分成块,并按需提供它们。可能也在使用AJAX,你可以有一个适合你需要的食谱。 使用“分而治之”机制,我认为您仍然可以使用常见的JSON解析方法。
希望有所帮助,
答案 3 :(得分:0)
浏览器中的JSON解析通常只使用eval完成,但在eval之前使用正则表达式“lint”,这样可以安全地评估JSON。
维基百科上有一个例子: