quick-x.客户端框架之excel表转换解析成lua文件

1 篇文章 0 订阅
1 篇文章 0 订阅

quick-x-05.客户端框架之excel表转换解析

解析约定

Excel导出的Txt的文本,约定

  1. 第一行为字段类型,
  2. 第二行为字段名称,
  3. 第三行以后’#’开头为字段注释,非’#’开头则为字段内容
  • 最终excel导出Txt文本如下图:
  • excel一键导出编码为ANSI的Txt(下面需要利用python将txt文本解析成客户端用lua文件,所以要注意编码) 点击这里

定制客户端所需的配置表文件、配表对应的实体文件

lua配置表,和lua配置表对应的实体文件。都是通过python解析对应的txt文本来获得。

客户端配表文件

期望的客户端配置表格式

我期望的txt转成的lua配置表格式为

local 配置表表名 = {
    {"第一行第一个字段的值", "第一行第二个字段的值", "第一行第三个字段的值"...},
    {"第一行第一个字段的值", "第一行第二个字段的值", "第一行第三个字段的值"...}
}
return 配置表表名

在开发过程中,可能会遇到某个字段是多个值,所以我们在excel中填充字段时,遇到字段为多个值时,用’|’来分隔开。

  • 如下图

最终的txt转成的lua配置表格式应该是这样的

local 配置表表名 = {
    {"第1行第1个字段的值", {"第1行第2个字段的1值","第1行第2个字段的2值"...}, "第1行第3个字段的值"...},
    {"第2行第1个字段的值", "第2行第2个字段的值", "第2行第3个字段的值"...}
}
return 配置表表名
利用python将txt转成期望的lua配表格式

操作记录:

  1. 按行读取文本数据,将每一行数据存在数组里(这里需要注意编码类型)
  2. 剔除变量类型行、变量名称行、变量注释行
  3. 将内容数据存到数组中,递归拼接字符写入到lua文件中
  • 部分示例代码(为了能减少篇幅,将一些容错删减掉了):

lines = [] # 转载该所有行
fp = open(filePath, "r")
line = fp.readline()
while len(line) != 0:
    line = line.replace('\r','')
    line = line.replace('\n','')
    lines.append(line) # 这里需要注意编码
    line = fp.readline()
fp.close()

# 排除变量类型行数据
column = len(lines[0]) 获取多少的个字段
del lines[0]

# 排除变量名字行数据
del lines[0]

# 排除注释行(注释行行数不定)
noteList = []
while len(lines) >0 and lines[0].startswith('#'):
    del lines[0]

# 将每一行数据存放到数组里面,若单元格为数组,则嵌套数组如:
# [
#   ["第1行第1个字段","第2行第2个字段"],
#   ["第1行第1个字段",["第2行第2个字段第1个值","第2行第2个字段第2个值"]],
# ]
contentList = []
for contentLine in lines: # 遍历行数据
    contentLineList = contentLine.split('\t') # 分割字符
    contentLineList = contentLineList[0:column]
    if contentLineList[0] != '': # 首元素不能为空
        tmpContentLineList = []
        for oneTab in contentLineList:
            if oneTab.find('|') != -1: # 单元格为table
                oneTabList = oneTab.split('|')
                if oneTabList[0] == '':
                    del oneTabList[0]
                tmpContentLineList.append(oneTabList)
            else:
                tmpContentLineList.append(oneTab)
        contentList.append(tmpContentLineList)

# 将list转成lua table
def listToLuaTabStr( oneList ):
    retStr = '{'
    for oneTab in oneList:
        if isinstance(oneTab,(list)) == True: # 如果是list就递归拼接
            retStr += listToLuaTabStr(oneTab)+','
        else:
            oneTab = oneTab.replace('\"','\\\"')
            retStr += '\"' +  oneTab + '\",'
    retStr += '}'
    return retStr

luaFp = codecs.open("路径+导出的lua文件名.lua","w","utf-8")
luaFp.write('local ' + "表名" + ' = \n{\n')
for oneList in contentList:
    writeStr = listToLuaTabStr(oneList)
    luaFp.write('\t'+writeStr+',\n')

luaFp.write('\n}\nreturn ' + dataName)
luaFp.close()
  • 最终导出的lua文件如下图:

客户端lua配表对应的实体lua文件

期望的客户端lua配置表对应的实体lua文件格式为

我期望的lua表对应的lua实体文件格式为

配置表表名 + "Lib" = class(配置表表名 + "Lib")

local 数据列表 = nil -- 数据队列
local 文件名称 = nil -- 文件名(不含扩展名)

-- 构造函数
function 配置表表名 + "Lib":ctor(list, fileName)
    self.字段名称1         = list[1]      -- 字段注释
    self.字段名称2         = list[2]      -- 字段注释

    self.key              = self.字段名称1  -- dataList存储key,key作为表索引

    if self.custom_ctor ~= nil then -- 自定义 ctor 部分
        self:custom_ctor()
    end
end

-- 注册函数
function 配置表表名 + "Lib".processData(dir, file)
    数据列表,文件名称 = LibraryManager.load(dir, file, 配置表表名 + "Lib")
end 

-- 根据id获取条目
function 配置表表名 + "Lib".getDataById(id)
    return 数据列表[id]
end

-- 获取所有条目
function 配置表表名 + "Lib".getDataList()
    return 数据列表
end

----------------------------BEGIN-------------------------------
-- 给用户留自定义部分。下次生产解析文件,不会被覆盖
-- TODO
-----------------------------END--------------------------------

return 配置表表名 + Lib
  1. 首先要保存用户自定义部分,保证下次字段修改,再次生成lua解析配表不会将用户自定义部分给覆盖掉。
  2. 其次提供几个公用函数,每个lua表对应的实体都会有的getDataById函数和getDataList函数。
  3. 最后就是字段名称和字段值、字段索引的行对应
  4. LibraryManager中对lua配表进行实体对象创建操作,下面会记录到
利用python写入对应的数据实体类

操作记录:

  1. 实体文件存在则先保存用户自定义部分内容,记录到数组中
  2. 写入变量名、变量值、变量注释。
  3. 将之前保存的用户自定义部分内容,从新写到实体文件中
  • 部分示例代码(为了能减少篇幅,将一些容错删减掉了):

# 写程序lib文件
def writeLuaLibFile(dataName,typeList,nameList,noteList):
    libClassName = dataName+'Lib'
    libFilePath = os.path.join(libDir,dataName+'Lib.lua')

    # 如果文件存在,需要保存用户自定义的内容
    extLines = []
    isExtLine = False
    if os.path.exists(libFilePath):
        readFp = codecs.open(libFilePath,"r","utf-8")
        oneLine = readFp.readline()
        if len(oneLine) != 0:
            # 去掉文件头说明
            oneLine = readFp.readline()
        while len(oneLine) != 0:
            if isExtLine == True:
                extLines.append(oneLine)
                if oneLine.find('START EXT END') != -1:
                    isExtLine = False
                    break
            else:
                if oneLine.find('START EXT BEGIN') != -1:
                    extLines.append(oneLine)
                    isExtLine = True
            oneLine = readFp.readline()
        readFp.close()

    libFp = codecs.open(libFilePath,"w","utf-8")
    libFp.write(libClassName + ' = class(\"' + libClassName + '\")\n\n')
    libFp.write('local dataList = nil -- 数据队列\n')
    libFp.write('local fileName = nil -- 文件名(不含扩展名)\n\n')

    libFp.write('-- 构造函数\n')
    libFp.write('function %s:ctor(list, fileName)\n' % libClassName)
    num = len(nameList)
    for i in range(0,num):
        oneProperty = nameList[i]
        leq = '\tself.%s' % oneProperty
        libFp.write(leq.ljust(30)+'= ') # 写字段
        if typeList[i] == 'INT':
            req = 'tonumber(list[%d])' % (i+1)
            libFp.write(req.ljust(25)+'-- ') # 写值
        else:
            req = 'list[%d]' % (i+1)
            libFp.write(req.ljust(25)+'-- ')
        # 写注释
        for note in noteList:
            libFp.write(note[i] + ' ')
        libFp.write('\n')

    libFp.write('\n')
    leq = '\tself.key'
    sKey = 'self.%s' % nameList[0]
    libFp.write(leq.ljust(30)+'= ' + sKey.ljust(25) + '-- dataList存储key\n')

    libFp.write('\t-- 自定义 ctor 部分\n')
    libFp.write('\tif self.custom_ctor ~= nil then\n')
    libFp.write('\t\tself:custom_ctor()\n')
    libFp.write('\tend\n')

    libFp.write('end\n\n')

    写入processData方法...
    #processData()

    写入getDataById方法...
    #getDataById()

    写入getDataList方法
    #getDataById()

    # 自定义扩展区间
    if len(extLines) == 0: # 原来的文件中不存在用户自定义代码
        libFp.write('----------------------------BEGIN-------------------------------\n')
        libFp.write('-- 给用户留自定义部分。下次生产解析文件,不会被覆盖\n\n')
        libFp.write('-----------------------------END--------------------------------\n\n')
    else: # 存在则将之前的用户自定义写入到新文件中
        for extLine in extLines:
            libFp.write(extLine)

    libFp.write('return ' + libClassName)
    libFp.close()
  • 最终导出的配表对应的实体类文件如下图:

LibraryManager文件中加载配表、创建配表模型对象

  • 示例解析代码:

LibraryManager = {}

--加载配表
--@param dir        lua配表文件路径
--@param file       lua配表文件名
--@param libClass   映射Class
--@return 返回分离数据table(table)、返回对应加载的文件名
function LibraryManager.load(dir, file, libClass)
    local tableData = require(dir .. file)
    local fileName = string.sub(file, 1, #file-#".lua") -- 截取文件名剔除.lua后缀
    local lib = {}
    local cls = nil
    for i = 1, #tableData do
        cls = libClass.new(tableData[i]) -- 每一行数据填充一个实体对象
        if lib[cls.key] ~= nil then
            SYSLog("##########Error:Key is not only, fileName:" .. fileName .. ", id:" .. tostring(cls.key))
        end
        lib[cls.key] = cls -- key做表索引
    end
    return lib, fileName
end

-- 加载所有配表
function LibraryManager.init()
    SYSLog("LibraryManager init start")
    ConfigLocalTextDataLib.processData(Config.CONFIG_PATH, "ConfigLocalTextData.lua") -- 多语言表
    -- TODO... other table data
    SYSLog("LibraryManager init end")
end

return LibraryManager
  1. LibraryManager.init()函数在进入游戏调用,来加载所有配置表,转成对象表模式
  2. LibraryManager.load()函数将每一行数据创建一个对应的实体对象,并返回一个实体表
  • 最终效果图

遇到的坑

  1. python在读取文件时(unicode(line, 'utf-8').decode('utf-8')),需要十分注意编码格式。excel中导出Txt一般为Unicode编码,这种编码在python中读取会报错。在excel中导出utf8操作实在是繁琐,所以利用vbs来一键导出ANSI编码的Txt
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值