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