见网站: http://www.json.org/
代码如下:
/* * Copyright (c) 2013 Calvin Rien * * Based on the JSON parser by Patrick van Bergen * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html * * Simplified it so that it doesn't throw exceptions * and can be used in Unity iPhone with maximum code stripping. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; namespace MiniJSON { // Example usage: // // using UnityEngine; // using System.Collections; // using System.Collections.Generic; // using MiniJSON; // // public class MiniJSONTest : MonoBehaviour { // void Start () { // var jsonString = "{ "array": [1.44,2,3], " + // ""object": {"key1":"value1", "key2":256}, " + // ""string": "The quick brown fox \"jumps\" over the lazy dog ", " + // ""unicode": "\u3041 Menu00fa sesiu00f3n", " + // ""int": 65536, " + // ""float": 3.1415926, " + // ""bool": true, " + // ""null": null }"; // // var dict = Json.Deserialize(jsonString) as Dictionary<string,object>; // // Debug.Log("deserialized: " + dict.GetType()); // Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]); // Debug.Log("dict['string']: " + (string) dict["string"]); // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); // // var str = Json.Serialize(dict); // // Debug.Log("serialized: " + str); // } // } /// <summary> /// This class encodes and decodes JSON strings. /// Spec. details, see http://www.json.org/ /// /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. /// All numbers are parsed to doubles. /// </summary> public static class Json { #region Parser sealed class Parser : IDisposable { const string WORD_BREAK = "{}[],:""; public static bool IsWordBreak(char c) { return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; } public static object Parse(string jsonString) { using (var instance = new Parser(jsonString)) return instance.ParseValue(); } enum TOKEN { NONE, CURLY_OPEN, CURLY_CLOSE, SQUARED_OPEN, SQUARED_CLOSE, COLON, COMMA, STRING, NUMBER, TRUE, FALSE, NULL }; StringReader m_json; Parser(string jsonString) { m_json = new StringReader(jsonString); } public void Dispose() { m_json.Dispose(); m_json = null; } object ParseValue() { TOKEN nextToken = NextToken; return ParseByToken(nextToken); } object ParseByToken(TOKEN token) { switch (token) { case TOKEN.STRING: return ParseString(); case TOKEN.NUMBER: return ParseNumber(); case TOKEN.CURLY_OPEN: return ParseObject(); case TOKEN.SQUARED_OPEN: return ParseArray(); case TOKEN.TRUE: return true; case TOKEN.FALSE: return false; case TOKEN.NULL: return null; default: return null; } } Dictionary<string, object> ParseObject() { var table = new Dictionary<string, object>(); // ditch opening brace m_json.Read(); // { while (true) { switch (NextToken) { case TOKEN.NONE: return null; case TOKEN.COMMA: continue; case TOKEN.CURLY_CLOSE: return table; default: // name string name = ParseString(); if (name == null) return null; // : if (NextToken != TOKEN.COLON) return null; // ditch the colon m_json.Read(); // value table[name] = ParseValue(); break; } } } List<object> ParseArray() { var array = new List<object>(); // ditch opening bracket m_json.Read(); // [ var parsing = true; while (parsing) { TOKEN nextToken = NextToken; switch (nextToken) { case TOKEN.NONE: return null; case TOKEN.COMMA: continue; case TOKEN.SQUARED_CLOSE: parsing = false; break; default: object value = ParseByToken(nextToken); array.Add(value); break; } } return array; } string ParseString() { var sb = new StringBuilder(); char c; // ditch opening quote m_json.Read(); bool parsing = true; while (parsing) { if (m_json.Peek() == -1) { parsing = false; break; } c = NextChar; switch (c) { case '"': parsing = false; break; case '\': if (m_json.Peek() == -1) { parsing = false; break; } c = NextChar; switch (c) { case '"': case '\': case '/': sb.Append(c); break; case 'b': sb.Append(''); break; case 'f': sb.Append('f'); break; case 'n': sb.Append(' '); break; case 'r': sb.Append(' '); break; case 't': sb.Append(' '); break; case 'u': var hex = new char[4]; for (int i = 0; i < 4; i++) { hex[i] = NextChar; } sb.Append((char)Convert.ToInt32(new string(hex), 16)); break; } break; default: sb.Append(c); break; } } return sb.ToString(); } object ParseNumber() { string number = NextWord; if (number.IndexOf('.') == -1) { long parsedInt; Int64.TryParse(number, out parsedInt); return parsedInt; } double parsedDouble; Double.TryParse(number, out parsedDouble); return parsedDouble; } void EatWhitespace() { while (Char.IsWhiteSpace(PeekChar)) { m_json.Read(); if (m_json.Peek() == -1) break; } } #region Properties char PeekChar { get { return Convert.ToChar(m_json.Peek()); } } char NextChar { get { return Convert.ToChar(m_json.Read()); } } string NextWord { get { var word = new StringBuilder(); while (!IsWordBreak(PeekChar)) { word.Append(NextChar); if (m_json.Peek() == -1) break; } return word.ToString(); } } TOKEN NextToken { get { EatWhitespace(); if (m_json.Peek() == -1) return TOKEN.NONE; switch (PeekChar) { case '{': return TOKEN.CURLY_OPEN; case '}': m_json.Read(); return TOKEN.CURLY_CLOSE; case '[': return TOKEN.SQUARED_OPEN; case ']': m_json.Read(); return TOKEN.SQUARED_CLOSE; case ',': m_json.Read(); return TOKEN.COMMA; case '"': return TOKEN.STRING; case ':': return TOKEN.COLON; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': return TOKEN.NUMBER; } switch (NextWord) { case "false": return TOKEN.FALSE; case "true": return TOKEN.TRUE; case "null": return TOKEN.NULL; } return TOKEN.NONE; } } #endregion } #endregion #region Serializer sealed class Serializer { StringBuilder m_builder; Serializer() { m_builder = new StringBuilder(); } public static string Serialize(object obj) { var instance = new Serializer(); instance.SerializeValue(obj); return instance.m_builder.ToString(); } void SerializeValue(object value) { IList asList; IDictionary asDict; string asStr; if (value == null) m_builder.Append("null"); else if ((asStr = value as string) != null) SerializeString(asStr); else if (value is bool) m_builder.Append((bool)value ? "true" : "false"); else if ((asList = value as IList) != null) SerializeArray(asList); else if ((asDict = value as IDictionary) != null) SerializeObject(asDict); else if (value is char) SerializeString(new string((char)value, 1)); else SerializeOther(value); } void SerializeObject(IDictionary obj) { bool first = true; m_builder.Append('{'); foreach (object e in obj.Keys) { if (!first) m_builder.Append(','); SerializeString(e.ToString()); m_builder.Append(':'); SerializeValue(obj[e]); first = false; } m_builder.Append('}'); } void SerializeArray(IList anArray) { m_builder.Append('['); bool first = true; foreach (object obj in anArray) { if (!first) m_builder.Append(','); SerializeValue(obj); first = false; } m_builder.Append(']'); } void SerializeString(string str) { m_builder.Append('"'); char[] charArray = str.ToCharArray(); foreach (var c in charArray) { switch (c) { case '"': m_builder.Append("\""); break; case '\': m_builder.Append("\\"); break; case '': m_builder.Append("\b"); break; case 'f': m_builder.Append("\f"); break; case ' ': m_builder.Append("\n"); break; case ' ': m_builder.Append("\r"); break; case ' ': m_builder.Append("\t"); break; default: int codepoint = Convert.ToInt32(c); if ((codepoint >= 32) && (codepoint <= 126)) m_builder.Append(c); else { m_builder.Append("\u"); m_builder.Append(codepoint.ToString("x4")); } break; } } m_builder.Append('"'); } void SerializeOther(object value) { // NOTE: decimals lose precision during serialization. // They always have, I'm just letting you know. // Previously floats and doubles lost precision too. if (value is float) { m_builder.Append(((float)value).ToString("R")); } else if (value is int || value is uint || value is long || value is sbyte || value is byte || value is short || value is ushort || value is ulong) { m_builder.Append(value); } else if (value is double || value is decimal) { m_builder.Append(Convert.ToDouble(value).ToString("R")); } else { SerializeString(value.ToString()); } } } #endregion /// <summary> /// Parses the string json into a value /// </summary> /// <param name="json">A JSON string.</param> /// <returns>An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false</returns> public static object Deserialize(string json) { // save the string for debug information if (json == null) return null; return Parser.Parse(json); } /// <summary> /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string /// </summary> /// <param name="json">A Dictionary<string, object> / List<object></param> /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns> public static string Serialize(object obj) { return Serializer.Serialize(obj); } } }