首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >非递归JavaScript JSON解析器

非递归JavaScript JSON解析器
EN

Stack Overflow用户
提问于 2010-08-24 22:27:16
回答 3查看 2.4K关注 0票数 16

我有一个非常大的JSON字符串,需要用浏览器中的JavaScript进行解析。现在,在一些浏览器中,我耗尽了堆栈空间。不幸的是,我的JSON可以包含用户字符串,所以我不能使用eval或者让浏览器解析它。

我看过一些标准的JavaScript JSON解析器,它们是递归的。我想知道是否有人知道任何安全且非递归的JSON解析器。我希望它有更少的特性--我只有一个巨大的对象数组。

或者,如果有人知道其中一个可能很容易修改,这也将是一个很大的帮助。

编辑:仔细检查,解析器内部使用的eval()会抛出堆栈溢出。所以,它必须是递归的。

EN

回答 3

Stack Overflow用户

发布于 2010-08-24 22:42:37

如果eval抛出stackoverflow,您可以使用以下代码

http://code.google.com/p/json-sans-eval/

一个根本不使用eval()的JSON解析器。

票数 5
EN

Stack Overflow用户

发布于 2011-09-04 15:14:57

我已经编写了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;
}
票数 3
EN

Stack Overflow用户

发布于 2010-08-24 22:44:32

我建议您将JSON字符串分成块,并按需提供它们。可能也在使用AJAX,你可以有一个适合你需要的菜谱。使用“分而治之”机制,我认为您仍然可以使用常见的JSON解析方法。

希望这能有所帮助,

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3557497

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档