CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
数据存储工具链

【数据存储】CSV 配置表解析:Excel 导出到 Lua 结构的完整流程

2026-09-20 08:51 作者:996 技术组 1 阅读 996引擎Lua教程传奇脚本
完整课程入口:996 全套课程体系Lua 学习路径幂尔框架 mirs.cn

实战应用:用在哪里

装备表、怪物表、商城价格表这类由策划在 Excel 维护的配置,导出 CSV 后由 Lua 解析成结构化 table,是配置管线的第一环。目标格式:按 id 索引的字典,字段名做 key,策划改表后无需改代码。

解析器实现:处理引号与换行

CSV 的两个陷阱:字段内含逗号(被引号包裹)、字段内含换行。简易逐字符状态机 40 行可写完:

lua
local function parseCSV(text)
    local rows, row, field, inQuote = {}, {}, "", false
    local i, n = 1, #text
    while i <= n do
        local c = text:sub(i, i)
        if inQuote then
            if c == '"' then
                if text:sub(i + 1, i + 1) == '"' then
                    field = field .. '"'; i = i + 1     -- 转义的引号
                else
                    inQuote = false
                end
            else field = field .. c end
        elseif c == '"' then inQuote = true
        elseif c == "," then row[#row + 1] = field; field = ""
        elseif c == "\n" then
            row[#row + 1] = field; rows[#rows + 1] = row
            row, field = {}, ""
        else field = field .. c end
        i = i + 1
    end
    if field ~= "" or #row > 0 then row[#row + 1] = field; rows[#rows + 1] = row end
    return rows
end

第一行是表头,第二行起是数据,按表头拼成字典:

lua
local rows = parseCSV(fileText)
local head = rows[1]
local items = {}
for r = 2, #rows do
    local item = {}
    for c = 1, #head do item[head[c]] = rows[r][c] end
    items[tonumber(item.id) or item.id] = item
end

三个工程细节

数字字段统一转码。 Excel 导出的数字是字符串,价格、概率字段必须 tonumber 收口,否则 price * 2 直接报错。空值归一。 CSV 空单元格解析出来是空串,按字段类型归一成 nil、0 或 false,避免下游判断 == "" 散落各处。加载耗时控制。 1 万行 x 20 列的表在 LuaJIT 下解析约 180ms,放进启动流程一次性执行;运行期只读解析结果,不做二次解析。

校验与错误报告

解析器必须能在入口处发现坏数据,否则一行错位的 CSV 会让下游业务全面报错。加载后按表头做三道校验:id 列必须存在且不重复(重复 id 打印行号并拒绝整表);数字列逐格 tonumber,转换失败收集到错误清单;必填列空值同样收集。三道校验全部通过才写入 items,任何一步失败保留上一版配置并打印报告:

lua
local errs = {}
if seen[item.id] then
    errs[#errs + 1] = ("行%d: id 重复 %s"):format(r, tostring(item.id))
end
if not tonumber(item.price) then
    errs[#errs + 1] = ("行%d: price 非数字 %s"):format(r, tostring(item.price))
end
if #errs > 0 then
    release_print("CSV 校验失败 " .. #errs .. " 条")
    for _, e in ipairs(errs) do release_print(e) end
    return false
end

错误报告带行号与字段名,策划改表后自己就能看懂哪里填错,运维不再充当人肉翻译。

热加载联动

CSV 解析器与配置中心对接后即可支持不重启更新:文件 MD5 变化触发重新解析,解析成功按引用原子替换,失败保留旧版。1 万行的表在 LuaJIT 下解析约 180ms,放进启动流程一次性执行;运行期只读解析结果,不做二次解析。配表流程定稿后,策划改 Excel → 导出 CSV → FTP 上传 → ConfigCenter:reload(),四步完成一次配置更新,全程不动代码。

← 返回文章地图返回研学路径