【发布时间】:2011-01-24 22:24:46
【问题描述】:
如果不使用 eval,我无法理解它是如何工作的 - 这背后的秘密是什么?
编辑:有人可以举一个简单的例子来说明树结构如何转换为对象吗?
【问题讨论】:
标签: javascript json parsing
如果不使用 eval,我无法理解它是如何工作的 - 这背后的秘密是什么?
编辑:有人可以举一个简单的例子来说明树结构如何转换为对象吗?
【问题讨论】:
标签: javascript json parsing
JSON 有一个well defined grammar,用于构造一棵树,然后将其转换为一个对象。
【讨论】:
eval 是如何实现的?
获取 Douglas Crockford 的书,Javascript: the Good Parts。附录 E 包括实现 JSON 解析器的代码。它不使用 eval。
【讨论】:
我不知道具体细节,但这并不难。只是读取字符和子字符串的智能组合,解释它们的含义并在您执行此操作时构建数据数组。像任何其他解析器一样。
【讨论】:
没有秘密。你认为 eval() 是如何实现的?它使用与解析 JSON 数据时必须使用的技术相同的技术,即有效地重新实现 eval() 的一部分。
【讨论】:
看看我的解析器有什么好主意。它并不完美,但代码很容易理解。
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;
}
【讨论】:
如何将带有 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 是数据的原生表示。它只是 JavaScript 内置对象格式的创造性实现。作为原生,它根本不需要被“解析”(从某种意义上说,程序员需要担心这样做)。
【讨论】: