From d02fb85b1c8625458e60f9eea59c37544a521f88 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Wed, 4 Feb 2026 17:15:18 +0800 Subject: [PATCH] json --- UniLua/LuaAuxLib.cs | 1 + UniLua/LuaJsonLib.cs | 526 ++++++++++++++++++++++++++++++++++++++ docs/cmleonos/docs/lua.md | 47 ++++ 3 files changed, 574 insertions(+) create mode 100644 UniLua/LuaJsonLib.cs diff --git a/UniLua/LuaAuxLib.cs b/UniLua/LuaAuxLib.cs index ec6dbd1..d551df0 100644 --- a/UniLua/LuaAuxLib.cs +++ b/UniLua/LuaAuxLib.cs @@ -589,6 +589,7 @@ namespace UniLua new NameFuncPair( LuaMathLib.LIB_NAME, LuaMathLib.OpenLib ), new NameFuncPair( LuaDebugLib.LIB_NAME, LuaDebugLib.OpenLib ), new NameFuncPair( LuaEncLib.LIB_NAME, LuaEncLib.OpenLib ), + new NameFuncPair( LuaJsonLib.LIB_NAME, LuaJsonLib.OpenLib ), }; for( var i=0; i ParseJsonObject(string json, ref int pos) + { + Dictionary dict = new Dictionary(); + string content = json.Substring(1, json.Length - 2); + int contentPos = 0; + + while (contentPos < content.Length) + { + contentPos = SkipWhitespace(content, contentPos); + + if (contentPos >= content.Length) + { + break; + } + + if (content[contentPos] == '}') + { + contentPos++; + break; + } + + string key = ParseJsonString(content, ref contentPos); + contentPos = SkipWhitespace(content, contentPos); + + if (contentPos >= content.Length || content[contentPos] != ':') + { + break; + } + contentPos++; + + object value = ParseJsonValue(content, ref contentPos); + if (key != null) + { + dict[key] = value; + } + + contentPos = SkipWhitespace(content, contentPos); + if (contentPos < content.Length && content[contentPos] == ',') + { + contentPos++; + } + } + + pos = contentPos; + return dict; + } + + private static List ParseJsonArray(string json, ref int pos) + { + List list = new List(); + string content = json.Substring(1, json.Length - 2); + int contentPos = 0; + + while (contentPos < content.Length) + { + contentPos = SkipWhitespace(content, contentPos); + + if (contentPos >= content.Length) + { + break; + } + + if (content[contentPos] == ']') + { + contentPos++; + break; + } + + object value = ParseJsonValue(content, ref contentPos); + if (value != null) + { + list.Add(value); + } + + contentPos = SkipWhitespace(content, contentPos); + if (contentPos < content.Length && content[contentPos] == ',') + { + contentPos++; + } + } + + pos = contentPos; + return list; + } + + private static object ParseJsonValue(string content, ref int pos) + { + pos = SkipWhitespace(content, pos); + + if (pos >= content.Length) + { + return null; + } + + char c = content[pos]; + + if (c == '{') + { + return ParseJsonObject(content, ref pos); + } + else if (c == '[') + { + return ParseJsonArray(content, ref pos); + } + else if (c == '"') + { + return ParseJsonString(content, ref pos); + } + else if (c == 't' || c == 'f' || c == 'n') + { + string keyword = ""; + while (pos < content.Length && char.IsLetter(content[pos])) + { + keyword += content[pos]; + pos++; + } + + if (keyword == "true") + { + return true; + } + else if (keyword == "false") + { + return false; + } + else if (keyword == "null") + { + return null; + } + + return null; + } + else if (char.IsDigit(c) || c == '-') + { + string numStr = ""; + while (pos < content.Length && (char.IsDigit(content[pos]) || content[pos] == '-' || content[pos] == '.')) + { + numStr += content[pos]; + pos++; + } + + if (double.TryParse(numStr, out double num)) + { + return num; + } + } + + return null; + } + + private static string ParseJsonString(string content, ref int pos) + { + if (pos >= content.Length || content[pos] != '"') + { + return null; + } + + pos++; + + StringBuilder sb = new StringBuilder(); + while (pos < content.Length) + { + char c = content[pos]; + pos++; + + if (c == '"') + { + break; + } + else if (c == '\\') + { + if (pos >= content.Length) + { + sb.Append('\\'); + break; + } + + pos++; + char escapeChar = content[pos]; + pos++; + + switch (escapeChar) + { + case '"': + sb.Append('"'); + break; + case '\\': + sb.Append('\\'); + break; + case '/': + sb.Append('/'); + break; + case 'b': + sb.Append('\b'); + break; + case 'f': + sb.Append('\f'); + break; + case 'n': + sb.Append('\n'); + break; + case 'r': + sb.Append('\r'); + break; + case 't': + sb.Append('\t'); + break; + case 'u': + if (pos + 3 < content.Length) + { + string hex = content.Substring(pos, 4); + if (int.TryParse(hex, System.Globalization.NumberStyles.HexNumber, null, out int code)) + { + sb.Append((char)code); + pos += 3; + } + } + break; + default: + sb.Append(escapeChar); + break; + } + } + else + { + sb.Append(c); + } + } + + return sb.ToString(); + } + + private static int SkipWhitespace(string content, int pos) + { + while (pos < content.Length && char.IsWhiteSpace(content[pos])) + { + pos++; + } + return pos; + } + + private static void PushLuaValue(ILuaState lua, object value) + { + if (value == null) + { + lua.PushNil(); + } + else if (value is bool) + { + lua.PushBoolean((bool)value); + } + else if (value is double) + { + lua.PushNumber((double)value); + } + else if (value is string) + { + lua.PushString((string)value); + } + else if (value is Dictionary) + { + lua.NewTable(); + foreach (var kvp in (Dictionary)value) + { + lua.PushString(kvp.Key); + PushLuaValue(lua, kvp.Value); + lua.SetField(-3, kvp.Key); + } + } + else if (value is List) + { + lua.NewTable(); + int index = 1; + foreach (var item in (List)value) + { + PushLuaValue(lua, item); + lua.RawSetI(-2, index++); + } + } + } + + private static string JsonEscapeString(string s) + { + if (string.IsNullOrEmpty(s)) + { + return ""; + } + + StringBuilder sb = new StringBuilder(); + foreach (char c in s) + { + switch (c) + { + case '"': + sb.Append("\\\""); + break; + case '\\': + sb.Append("\\\\"); + break; + case '\b': + sb.Append("\\b"); + break; + case '\f': + sb.Append("\\f"); + break; + case '\n': + sb.Append("\\n"); + break; + case '\r': + sb.Append("\\r"); + break; + case '\t': + sb.Append("\\t"); + break; + default: + sb.Append(c); + break; + } + } + return sb.ToString(); + } + + private static int Json_Null(ILuaState lua) + { + lua.PushNil(); + return 1; + } + + private static int Json_Parse(ILuaState lua) + { + return Json_Decode(lua); + } + + private static int Json_Stringify(ILuaState lua) + { + return Json_Encode(lua); + } + } +} \ No newline at end of file diff --git a/docs/cmleonos/docs/lua.md b/docs/cmleonos/docs/lua.md index 58e4daf..47837ce 100644 --- a/docs/cmleonos/docs/lua.md +++ b/docs/cmleonos/docs/lua.md @@ -1086,7 +1086,54 @@ print(decoded) ``` --- +## JSON 库 +### json.encode(table) +将 Lua 表编码为 JSON 字符串。 + +```lua +local data = {name = "John", age = 30} +local jsonStr = json.encode(data) +print(jsonStr) +``` + +### json.decode(string) +将 JSON 字符串解码为 Lua 表。 + +```lua +local jsonStr = '{"name": "John", "age": 30}' +local data = json.decode(jsonStr) +print(data.name) +print(data.age) +``` + +### json.null() +返回 null 值。 + +```lua +local nullValue = json.null() +print(nullValue) +``` + +### json.parse(string) +解析 JSON 字符串(同 decode)。 + +```lua +local jsonStr = '{"name": "John", "age": 30}' +local data = json.parse(jsonStr) +print(data.name) +``` + +### json.stringify(table) +将 Lua 表转换为 JSON 字符串(同 encode)。 + +```lua +local data = {name = "John", age = 30} +local jsonStr = json.stringify(data) +print(jsonStr) +``` + +--- ## 包库 (package) ### package.loaded