using XGame.Framework.Utils; using System; using System.Collections.Generic; using System.Globalization; using System.Text; namespace XGame.Framework.Json { public class JsonParsor { private const int TokenNone = 0; /// /// 花括号 { /// private const int TokenCurlyOpen = 1; /// /// 花括号 } /// private const int TokenCurlyClose = 2; /// /// /// private const int TokenSquaredOpen = 3; /// /// 方括号 ] /// private const int TokenSquaredClose = 4; /// /// 冒号 : /// private const int TokenColon = 5; /// /// 逗号 , /// private const int TokenComma = 6; /// /// 字符串 string /// private const int TokenString = 7; /// /// 数字 number /// private const int TokenNumber = 8; /// /// bool值 true /// private const int TokenTrue = 9; /// /// bool值 false /// private const int TokenFalse = 10; /// /// 空 null /// private const int TokenNull = 11; public bool TryDeserializeObject(string json, out object obj) { bool success = true; obj = null; if (json != null) { char[] charArray = json.ToCharArray(); int index = 0; obj = ParseValue(charArray, ref index, ref success); //PrintDict(obj); } return success; } #region 对json进行解析 // 开始处理json字符串的每个字符 private object ParseValue(char[] json, ref int index, ref bool success) { switch (LookAhead(json, index)) { case TokenString: return ParseString(json, ref index, ref success); case TokenNumber: return ParseNumber(json, ref index, ref success); case TokenCurlyOpen: return ParseObject(json, ref index, ref success); case TokenSquaredOpen: return ParseArray(json, ref index, ref success); case TokenTrue: NextToken(json, ref index); return true; case TokenFalse: NextToken(json, ref index); return false; case TokenNull: NextToken(json, ref index); return null; case TokenNone: break; } success = false; return null; } // 特殊字符跳过 private void DealWithWhitespace(char[] json, ref int index) { for (int length = json.Length; index < length; index++) { if (" \t\n\r\b\f".IndexOf(json[index]) == -1) break; } } // 前瞻 private int LookAhead(char[] json, int index) { int saveIndex = index; return NextToken(json, ref saveIndex); } // json字符判断 private int NextToken(char[] json, ref int index) { DealWithWhitespace(json, ref index); if (index == json.Length) return TokenNone; char c = json[index]; index++; // 字符判断 switch (c) { case '{': return TokenCurlyOpen; case '}': return TokenCurlyClose; case '[': return TokenSquaredOpen; case ']': return TokenSquaredClose; case ':': return TokenColon; case ',': return TokenComma; case '"': return TokenString; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': return TokenNumber; } // 剩余字符长度 index--; int remainingLength = json.Length - index; // 字符串false if (remainingLength >= 5) { if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && json[index + 4] == 'e') { index += 5; return TokenFalse; } } // 字符串true if (remainingLength >= 4) { if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e') { index += 4; return TokenTrue; } } // 字符串null if (remainingLength >= 4) { if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l') { index += 4; return TokenNull; } } return TokenNone; } #region ParseString private string ParseString(char[] json, ref int index, ref bool success) { StringBuilder builder = StringBuilderUtils.Acquire(); DealWithWhitespace(json, ref index); char c = json[index++]; bool complete = false; while (!complete) { if (index == json.Length) break; c = json[index++]; switch (c) { case '"': complete = true; break; case '\\': if (index == json.Length) break; c = json[index++]; switch (c) { case '"': builder.Append('"'); break; case '\\': builder.Append('\\'); break; case '\'': builder.Append('\''); break; case '/': builder.Append('/'); break; case 'b': builder.Append('\b'); break; case 'f': builder.Append('\f'); break; case 'n': builder.Append('\n'); break; case 'r': builder.Append('\r'); break; case 't': builder.Append('\t'); break; case 'u': int remainingLength = json.Length - index; if (remainingLength >= 4) { uint codePoint; // 将32位十六进制解析为无符号整型 if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) throw new SystemException("can not parse the 32 bit hex into an integer codepoint"); // 将整型转换为unicode字符并添加到字符串中 if (0xD800 <= codePoint && codePoint <= 0xDBFF) // if high surrogate { index += 4; // skip 4 chars remainingLength = json.Length - index; if (remainingLength >= 6) { uint lowCodePoint; if (new string(json, index, 2) == "\\u" && UInt32.TryParse(new string(json, index + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out lowCodePoint)) { if (0xDC00 <= lowCodePoint && lowCodePoint <= 0xDFFF) // if low surrogate { builder.Append((char)codePoint); builder.Append((char)lowCodePoint); index += 6; // skip 6 chars continue; } } } success = false; // invalid surrogate pair StringBuilderUtils.Release(builder); return ""; } builder.Append(ConvertFromUtf32((int)codePoint)); // skip 4 chars index += 4; } break; } break; default: builder.Append(c); break; } } if (!complete) { success = false; StringBuilderUtils.Release(builder); return null; } return StringBuilderUtils.GetStringAndRelease(builder); } // Unicode编码转换为UTF-32 private string ConvertFromUtf32(int utf32) { if (utf32 < 0 || utf32 > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(utf32), "The argument must be from 0 to 0x10FFFF."); if (0xD800 <= utf32 && utf32 <= 0xDFFF) throw new ArgumentOutOfRangeException(nameof(utf32), "The argument must not be in surrogate pair range."); if (utf32 < 0x10000) return new string((char)utf32, 1); utf32 -= 0x10000; return new string(new char[] { (char)((utf32 >> 10) + 0xD800), (char)(utf32 % 0x0400 + 0xDC00) }); } #endregion #region ParseNumber private object ParseNumber(char[] json, ref int index, ref bool success) { DealWithWhitespace(json, ref index); // 获取数字的字符串 int lastIndex = GetLastIndexOfNumber(json, index); int numLength = (lastIndex - index) + 1; string numStr = new string(json, index, numLength); object changeNum; if (numStr.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1 || numStr.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1) { success = double.TryParse(new string(json, index, numLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); changeNum = number; } else { success = long.TryParse(new string(json, index, numLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); changeNum = number; } index = lastIndex + 1; return changeNum; } private int GetLastIndexOfNumber(char[] json, int index) { int lastIndex = index; for (int length = json.Length; lastIndex < length; lastIndex++) { if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) break; } return lastIndex - 1; } #endregion #region ParseObject private Dictionary ParseObject(char[] json, ref int index, ref bool success) { Dictionary map = new Dictionary(); DealWithWhitespace(json, ref index); // 跳过 { index++; int token = index; bool complete = false; while (!complete) { token = LookAhead(json, index); switch (token) { case TokenNone: success = false; return null; case TokenComma: NextToken(json, ref index); break; case TokenCurlyClose: NextToken(json, ref index); return map; default: // key string key = ParseString(json, ref index, ref success); if (!success) return null; // : token = NextToken(json, ref index); if (token != TokenColon) { success = false; return null; } // value object value = ParseValue(json, ref index, ref success); if (!success) return null; map.Add(key, value); break; } } return map; } #endregion #region ParseArray private List ParseArray(char[] json, ref int index, ref bool success) { List list = new List(); DealWithWhitespace(json, ref index); index++; int token = index; bool complete = false; while (!complete) { token = LookAhead(json, index); switch (token) { case TokenNone: success = false; return null; case TokenComma: NextToken(json, ref index); break; case TokenSquaredClose: NextToken(json, ref index); complete = true; break; default: // value object value = ParseValue(json, ref index, ref success); if (!success) return null; list.Add(value); break; } } return list; } #endregion #endregion } }