【问题标题】:Can someone explain how JSON parsers work without using eval at all?有人可以解释 JSON 解析器如何在不使用 eval 的情况下工作吗?
【发布时间】:2011-01-24 22:24:46
【问题描述】:

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

编辑:有人可以举一个简单的例子来说明树结构如何转换为对象吗?

【问题讨论】:

标签: javascript json parsing


【解决方案1】:

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

【讨论】:

  • 但是树是如何转换成对象的呢?
  • @Fedor - 你的要求等同于“JSON 解析器是如何实现的”...
  • @Fedor - eval 是如何实现的?
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      没有秘密。你认为 eval() 是如何实现的?它使用与解析 JSON 数据时必须使用的技术相同的技术,即有效地重新实现 eval() 的一部分。

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

          • 您知道...从技术上讲,您的 JSON 字符串示例不是有效的 JSON。 :-p
          • 我并不想在这里做得非常正确,只是让他朝着正确的方向前进。我也返回了一个哈希而不是一个数组
          【解决方案7】:

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

          【讨论】:

          • 你在说什么,eval() 是一个适合 JSON 的解析器。没错,但这不是 OP 的意义所在。
          猜你喜欢
          • 1970-01-01
          • 2012-03-27
          • 1970-01-01
          • 2011-09-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-25
          • 2021-05-16
          相关资源
          最近更新 更多