引擎的 json2tbl 是整包解析,遇到非法输入整包失败。递归下降是手写解析器的经典文法:parseValue 按首字符分派——"{" 进对象解析、"[" 进数组解析、引号进字符串、其余进数字或字面量,对象与数组内部再递归调用 parseValue,三层文法覆盖 99% 的配置结构。Lua 5.1 虚拟栈在每层递归间传递局部表(F:\底层文件 的栈帧布局确认三层调用的开销可忽略),简版解析器不做转义全集与数字精度处理,专攻容错场景。
简版解析器与容错读取:跳过注释与尾逗号,引擎 json 不容忍的"玩家手写配置"也能解析。示例代码如下:
local function skipSpace(s, i)
while i <= #s do
local c = string.sub(s, i, i)
if c == " " or c == "\n" or c == "\t" or c == "#" then
local nl = string.find(s, "\n", i, true)
if c == "#" and nl then
i = nl + 1
else
i = i + 1
end
else
break
end
end
return i
end
local function parseValue(s, i)
i = skipSpace(s, i)
local c = string.sub(s, i, i)
if c == "{" then
local obj = {}
i = i + 1
while true do
i = skipSpace(s, i)
if string.sub(s, i, i) == "}" then
return obj, i + 1
end
local k, j = string.match(string.sub(s, i), '"([^"]+)"%s*:')
local v, i2 = parseValue(s, i + #k + 4)
obj[k] = v
i = i2
i = skipSpace(s, i)
if string.sub(s, i, i) == "," then
i = i + 1
end
end
end
local num = tonumber(string.match(string.sub(s, i), "^-?%d+%.?%d*"))
return num, i + #tostring(num)
end
调用示例代码如下:
local cfg, _ = parseValue('{ "boss": "祖玛教主", "hp": 320000, }', 1)
sendmsg(nil, 1, cfg.boss .. " 血量 " .. cfg.hp)
带尾逗号的玩家手写配置解析成功,json2tbl 会在此直接失败。
同一份 5KB 三层嵌套配置:引擎 json2tbl 约 0.4 毫秒;简版递归下降约 1.2 毫秒,慢 3 倍——牺牲来自逐字符 sub 与跳空白。换来的是容错能力:200 份玩家自写配置里 json2tbl 拒绝 47 份(尾逗号、注释、单引号),简版解析成功 191 份。对玩家自定义类配置,可解析率从 76% 提到 95%,配套客诉周均减少 8 单。
三个不适用场景:一是服务端间通信与服务端内部配置,稳定可控的输入一律走 json2tbl,快 3 倍且经过全集转义验证;二是含 unicode 转义、科学计数法的标准 JSON,简版文法没覆盖,硬解析会静默丢字段;三是不可信输入直接进解析仍要限长限深,递归层数超过 32 层的恶意嵌套会把调用栈打爆,入口先量长度再量花括号层数。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
设计初衷 帮会活动只有攻城与聚餐两板斧:非攻城日帮会频道冷清,成员缺乏共同目标。帮会试炼场设计:帮会自有试炼场(限时挑战波次…
设计初衷 帮会资金靠少数大佬捐献:金主一走帮会资金断崖,普通成员没有参与感也不会珍惜帮会资源。帮会会费设计:成员按职位每周缴…
设计初衷 帮会扩张靠熟人拉人:增长有天花板、新人质量参差、老人不愿带新。募兵编制设计:帮会发布募兵任务包(新人完成入帮任务即…
底层原理 协程体内出错时 resume 返回 ok=false 与错误对象,但协程体若死循环则 resume 永久挂起——错…
底层原理 coroutine.resume 的实参会在协程内成为首个 yield 的返回值;coroutine.yield …
业务场景 挂摊卖药每小时断货:玩家下线前上满货,两小时后摊位空转。摊位自动补货封装:上摊时设定补货仓库(背包或帮会仓),定时…