有人可以解释JSON解析器如何工作而不使用eval吗?

时间:2010-03-08 10:40:48

标签: javascript json parsing

如果不使用eval,我无法理解它是如何工作的 - 这背后的秘密是什么?

编辑:有人可以提供一个关于如何将树结构转换为对象的简单示例吗?

7 个答案:

答案 0 :(得分:9)

JSON有一个well defined grammar,用于构造一个树,然后将其转换为一个对象。

答案 1 :(得分:3)

获取Douglas Crockford的书, Javascript:Good Parts 。附录E包括实现JSON解析器的代码。它不使用eval。

答案 2 :(得分:2)

我不知道具体细节,但这并不难。只是读取字符和子字符串的智能组合,解释它们的含义并在您执行操作时构建数据数组。像任何其他解析器一样。

答案 3 :(得分:2)

没有秘密。您如何看待eval()的实施?如果你必须解析JSON数据,它会使用你必须使用的相同技术,即有效地重新实现eval()的一部分。

答案 4 :(得分:2)

看看我的解析器是个好主意。它并不完美,但代码很容易理解。

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;
}

答案 5 :(得分:1)

如何将带有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

答案 6 :(得分:0)

JSON是数据的原生表示。它只是JavaScript内置对象格式的创造性实现。作为原生,它根本不需要“解析”(在程序员需要担心这样做的意义上)。