Может кто-нибудь объяснить, как работают парсеры JSON без использования eval? - PullRequest
3 голосов
/ 08 марта 2010

Я не могу понять, как это работает, не используя eval - в чем секрет?

Редактировать: Может ли кто-нибудь представить тривиальный пример того, как древовидная структура преобразуется в объект?

Ответы [ 7 ]

9 голосов
/ 08 марта 2010

JSON имеет четко определенную грамматику , которая используется для построения дерева, которое затем преобразуется в объект.

3 голосов
/ 24 мая 2010

Получить книгу Дугласа Крокфорда, Javascript: Хорошие детали . Приложение E содержит код, реализующий синтаксический анализатор JSON. Не использует eval.

2 голосов
/ 24 мая 2010

Посмотрите на мой парсер для хорошей идеи. Он не идеален, но за кодом довольно легко следовать.

public static JsonStructure Parse(string jsonText)
{
    var result = default(JsonStructure);
    var structureStack = new Stack<JsonStructure>();
    var keyStack = new Stack<string>();
    var current = default(JsonStructure);
    var currentState = ParserState.Begin;
    var key = default(string);
    var value = default(object);

    foreach (var token in Lexer.Tokenize(jsonText))
    {
        switch (currentState)
        {
            case ParserState.Begin:
                switch (token.Type)
                {
                    case TokenType.BeginObject:
                        currentState = ParserState.Name;
                        current = result = new JsonObject();
                        break;
                    case TokenType.BeginArray:
                        currentState = ParserState.Value;
                        current = result = new JsonArray();
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.Name:
                switch (token.Type)
                {
                    case TokenType.String:
                        currentState = ParserState.NameSeparator;
                        key = (string)token.Value;
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.NameSeparator:
                switch (token.Type)
                {
                    case TokenType.NameSeparator:
                        currentState = ParserState.Value;
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.Value:
                switch (token.Type)
                {
                    case TokenType.Number:
                    case TokenType.String:
                    case TokenType.True:
                    case TokenType.False:
                    case TokenType.Null:
                        currentState = ParserState.ValueSeparator;
                        value = token.Value;
                        break;
                    case TokenType.BeginObject:
                        structureStack.Push(current);
                        keyStack.Push(key);
                        currentState = ParserState.Name;
                        current = new JsonObject();
                        break;
                    case TokenType.BeginArray:
                        structureStack.Push(current);
                        currentState = ParserState.Value;
                        current = new JsonArray();
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.ValueSeparator:
                var jsonObject = (current as JsonObject);
                var jsonArray = (current as JsonArray);
                if (jsonObject != null)
                {
                    jsonObject.Add(key, value);
                    currentState = ParserState.Name;
                }
                if (jsonArray != null)
                {
                    jsonArray.Add(value);
                    currentState = ParserState.Value;
                }
                switch (token.Type)
                {
                    case TokenType.EndObject:
                    case TokenType.EndArray:
                        currentState = ParserState.End;
                        break;
                    case TokenType.ValueSeparator:
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            case ParserState.End:
                switch (token.Type)
                {
                    case TokenType.EndObject:
                    case TokenType.EndArray:
                    case TokenType.ValueSeparator:
                        var previous = structureStack.Pop();
                        var previousJsonObject = (previous as JsonObject);
                        var previousJsonArray = (previous as JsonArray);
                        if (previousJsonObject != null)
                        {
                            previousJsonObject.Add(keyStack.Pop(), current);
                            currentState = ParserState.Name;
                        }
                        if (previousJsonArray != null)
                        {
                            previousJsonArray.Add(current);
                            currentState = ParserState.Value;
                        }
                        if (token.Type != TokenType.ValueSeparator)
                        {
                            currentState = ParserState.End;
                        }
                        current = previous;
                        break;
                    default:
                        throw new JsonException(token, currentState);
                }
                break;
            default:
                break;
        }
    }
    return result;
}
2 голосов
/ 08 марта 2010

Секрета нет. Как вы думаете, eval () реализован? Он использует те же методы, которые вы должны были бы использовать, если бы вам пришлось анализировать данные JSON, то есть эффективно переопределить часть eval ().

2 голосов
/ 08 марта 2010

Я не знаю специфики, но это не очень сложно. Просто умная комбинация чтения символов и подстрок, интерпретации их значения и создания массива данных в процессе работы. Как и любой другой парсер.

1 голос
/ 24 мая 2010

тривиальный пример того, как преобразовать строку с json в объект без eval:

  var txt='[\'one\',\'two\']';

  var re1='(\\[)';  // Any Single Character 1
  var re2='(\\\'.*?\\\')';  // Single Quote String 1
  var re3='(,)';    // Any Single Character 2
  var re4='(\\\'.*?\\\')';  // Single Quote String 2
  var re5='(\\])';  // Any Single Character 3

  var p = new RegExp(re1+re2+re3+re4+re5,["i"]);
  var m = p.exec(txt);
  if (m != null)
  {
      var c1=m[1];
      var s1=m[2];
      var c2=m[3];
      var s2=m[4];
      var c3=m[5];

      return [s1, s2];
  }
  return null;

да, это ужасный способ сделать это, но он делает то, что требует для этой строки: p

0 голосов
/ 08 марта 2010

JSON является собственным представлением данных. Это просто творческая реализация встроенного в JavaScript формата объектов. Будучи нативным, его вообще не нужно «анализировать» (в том смысле, что программисту нужно беспокоиться об этом).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...