Подтвердить что ты не робот

Нерекурсивный JavaScript JSON-парсер

У меня очень большая строка JSON, которую мне нужно проанализировать с помощью JavaScript-браузера. Прямо сейчас, в нескольких браузерах, у меня заканчивается пространство стека. К сожалению, мой JSON может содержать пользовательские строки, поэтому я не могу использовать eval или иначе разрешать браузеру его анализировать.

Я просмотрел несколько стандартных JavaScript JSON-парсеров, и они являются рекурсивными. Интересно, знает ли кто-нибудь обозреватель JSON, который является безопасным и нерекурсивным. Я бы хотел, чтобы у него было меньше возможностей - у меня просто огромный массив объектов.

В качестве альтернативы, если кто-то знает о том, что может быть легко модифицировать, это тоже будет большой помощью.

EDIT: при ближайшем рассмотрении переполнение стека вызывается eval(), используемым внутри анализатора. Поэтому он должен быть рекурсивным.

4b9b3361

Ответ 1

Разбор JSON в браузере обычно выполняется с помощью только eval, но предшествует eval с регулярным выражением "lint", что должно сделать его безопасным для оценки JSON.

В википедии есть пример:

Ответ 2

Если eval выбрасывает stackoverflow, вы можете использовать этот

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

Парсер JSON, который вообще не использует eval().

Ответ 3

Я написал json parsers, которые не являются рекурсивными на нескольких языках, но до сих пор не в 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;
}

Ответ 4

Я рекомендую вам разделить строку JSON на куски и принести их по требованию. Может быть, и AJAX, у вас может быть рецепт, который будет соответствовать вашим потребностям. Используя механизм "разделяй и властвуй", я думаю, вы все равно можете использовать общие методы разбора JSON.

Надеюсь, что это поможет,