MSIPO技术圈 首页 IT技术 查看内容

Python XLSX导出到LuaTable

2024-03-29

XLSX配置表直接导出到LuaTable
导出的时候把key进行抽离出__key__ 节约内存占用 逻辑中通过__index进行映射

XLSX数据

在这里插入图片描述

工具代码

#先安装第三方库
pip install pandas 
import pandas as pd
import math

INT_TYPE = 'int'
BOOL_TYPE = 'bool'
STRING_TYPE = 'string'
FLOAT_TYPE = 'float'
INT_ARRAY_TYPE = 'int[]'
BOOL_ARRAY_TYPE = 'bool[]'
STRING_ARRAY_TYPE = 'string[]'
FLOAT_ARRAY_TYPE = 'float[]'

VALUE_NAME = '__value__'
INDEX_NAME = '__index__'
KEY_NAME = '__key__'
LEN_NAME = 'len'

def isnan(value):
    try:
        # 尝试将值转换为浮点数
        float_value = float(value)
        return math.isnan(float_value)
    except (TypeError, ValueError):
        # 如果转换失败,说明值不是数字或NaN
        return False

def readXlsx(xlsxPath):
    df = pd.read_excel(xlsxPath, header=None)
    return df

def FrmatIntArray(text):
    return '{' + text + '}'

def FrmatFloatArray(text):
    return '{' + text + '}'

def FrmatStringArray(text):
    outStr = "{"
    for value in text.split(','):
        outStr += f'"{value}",'
    
    outStr = outStr[:len(outStr) - 1]
    outStr += "}"
    return outStr

def FrmatBoolArray(text):
    outStr = "{"
    for value in text.split(','):
        outStr += str(bool(int(value))).lower() + ","
    
    outStr = outStr[:len(outStr) - 1]
    outStr += "}"
    return outStr

def FormatValue(value, type):
    if pd.isna(value):  # 处理空值
        if type == INT_TYPE or type == FLOAT_TYPE:
            value = 0
        elif type == STRING_TYPE:
            value = '""'
        elif type == BOOL_TYPE:
            value = 'false'
        elif type == INT_ARRAY_TYPE or type == STRING_ARRAY_TYPE or type == BOOL_ARRAY_TYPE or type == FLOAT_ARRAY_TYPE:
            value = '{}'
    else:
        value = str(value).strip()  # 去除字符串两端的空格

        # 根据字段类型进行处理
        if type == STRING_TYPE:
            value = f'"{value}"'
        elif type == INT_TYPE:
            value = int(value)
        elif type == FLOAT_TYPE:
            value = float(value)
        elif type == BOOL_TYPE:
            value = str(bool(value)).lower()
        elif type == INT_ARRAY_TYPE:
            value = FrmatIntArray(value)
        elif type == STRING_ARRAY_TYPE:
            value = FrmatStringArray(value)
        elif type == BOOL_ARRAY_TYPE:
            value = FrmatBoolArray(value)
        elif type == FLOAT_ARRAY_TYPE:
            value = FrmatFloatArray(value)
    
    return value

def toTable(xlsxPath, tableName):
    df = readXlsx(xlsxPath)
    # 获取字段名和类型
    field_names = list(df.iloc[1])
    field_types = list(df.iloc[2])
    key2Index = {}
    Index2Id = {}
    length = 0

    table = '--The generated code cannot be modified!!\n'
    table+=(tableName + ' = {} \nlocal ' + f'{VALUE_NAME} = ' + '{\n')
    # 遍历每一行数据,从第四行开始
    for index, row in df.iloc[3:].iterrows():
        # 获取行的 ID(假设 ID 在第一列)
        row_id = row[0]
        table+=(f'    [{row_id}] = {{')
        length+=1
        Index2Id[length] = row_id
        # 遍历每一列数据(不包括第一列)
        for column, value in row.items():
            # 获取字段类型
            field_type = field_types[column]
            field_name = field_names[column]

            if isnan(field_type) or isnan(field_name):
                continue

            value = FormatValue(value, field_type)
            key2Index[field_name] = column + 1
            table+=(f'{value}, ')

        table = table[:len(table) - 2]
        table+=('},\n')

    # 写入 Lua 的 table 结束部分
    table+=('}\n\n')
    table+=('local ' + f'{KEY_NAME} = ' + '{\n')
    for key, value in key2Index.items():
        table+=(f'   {key} = {value},\n')
    table+=('}\n\n')

    table+=('local ' + f'{INDEX_NAME} = ' + '{')
    for key, value in Index2Id.items():
        table+=(f'{value},')
    table = table[:len(table) - 1]
    table+=('}\n')

    table+=(f'{tableName}.{LEN_NAME} = ' + f'{length}' + '\n\n')

    #GetValue
    table+=('local function GetValue(tTable, vKey)\n')
    table+=(f'\tlocal nIndex = {KEY_NAME}[vKey]\n')
    table+=('\tif not nIndex then\n\t\treturn nil\n\tend\n\n\treturn tTable[nIndex]\nend\n\n')

    #Get
    table+=('local function Get(tTable, vKey)\n')
    table+=(f'\tif vKey == "tMap" then\n\t\treturn {VALUE_NAME}\n\tend\n\n')
    table+=(f'\tif vKey == "tList" then\n\t\treturn {INDEX_NAME}\n\tend\n\n')
    table+=(f'\treturn {VALUE_NAME}[vKey]\nend\n\n')

    table+=(f'local function ReadOnly(tTable, vKey, vValue)\n\tprint("{tableName} A read-only table cannot be modified, key: "..vKey.." be changed to: "..vValue)\nend\n\n')
    table+=(f'for nId, tCfg in pairs({VALUE_NAME}) do\n\t' + 'setmetatable(tCfg, {__index = GetValue, __newindex = ReadOnly})\nend\n\n')
    table+=(f'setmetatable({tableName}, ' + '{__index = Get, __newindex = ReadOnly})')

    return table

def writeTable(tablePath, table):
    with open(tablePath, 'w', encoding="utf-8") as f:
        f.write(table)

tableName = 'TestTable'
table = toTable('XlsxToLuaTable\Test.xlsx', tableName)
writeTable('XlsxToLuaTable\\' + tableName + '.lua', table)

XLSX输出的结果

对于外部而言 这个Table里内容是不可以直接访问得 除了TestTable.len
Table中的内容也不会被修改使用__newindex进行约束 把table变为只读 如果尝试修改静态数据 会报错

--The generated code cannot be modified!!
TestTable = {} 
local __value__ = {
    [10086] = {10086, "超赛1", true, 20, 160, 23.33, {101,102,103,104}, {true,false,false,false}, {"描述1","描述2","描述3","描述4"}, {10.2,10.3,10.4,10.5}},
    [10087] = {10087, "超赛2", true, 21, 161, 24.33, {101,102,103,104}, {true,false,true,true}, {"描述1","描述2","描述3","描述5"}, {10.2,10.3,10.4,10.6}},
    [10088] = {10088, "超赛3", true, 22, 162, 25.33, {101,102,103,104}, {true,false,true,false}, {"描述1","描述2","描述3","描述6"}, {10.2,10.3,10.4,10.7}},
    [10089] = {10089, "超赛4", true, 23, 163, 26.33, {101,102,103,104}, {true,false,true,true}, {"描述1","描述2","描述3","描述7"}, {10.2,10.3,10.4,10.8}},
    [10090] = {10090, "超赛5", true, 24, 164, 27.33, {101,102,103,104}, {true,false,false,false}, {"描述1","描述2","描述3","描述8"}, {10.2,10.3,10.4,10.9}},
}

local __key__ = {
   ID = 1,
   Name = 2,
   Sex = 3,
   Age = 4,
   Height = 5,
   Width = 6,
   skillIds = 7,
   skillOpens = 8,
   skillDesc = 9,
   cds = 10,
}

local __index__ = {10086,10087,10088,10089,10090}
TestTable.len = 5

local function GetValue(tTable, vKey)
	local nIndex = __key__[vKey]
	if not nIndex then
		return nil
	end

	return tTable[nIndex]
end

local function Get(tTable, vKey)
	if vKey == "tMap" then
		return __value__
	end

	if vKey == "tList" then
		return __index__
	end

	return __value__[vKey]
end

local function ReadOnly(tTable, vKey, vValue)
	print("TestTable A read-only table cannot be modified, key: "..vKey.." be changed to: "..vValue)
end

for nId, tCfg in pairs(__value__) do
	setmetatable(tCfg, {__index = GetValue, __newindex = ReadOnly})
end

setmetatable(TestTable, {__index = Get, __newindex = ReadOnly})

逻辑内使用这些配置

local Len = TestTable.len --获取table长度
local tMap = TestTable.tMap --获取整个配置 key是id value是整行数据
local tList = TestTable.tList --获取整个配置的id 是个数组
local tItem = tMap[10086] --获取一行数据
local tItem1 = TestTable[10086] --获取一行数据 不同的写法而已 这样写简单不用先获取tMap
local sName = tItem.Name --获取一行中的某个数据 Name是XLSX配置表中的字段
local sDesc = tItem.skillDesc --获取一行中的某个数据 skillDesc 是XLSX配置表中的字段

运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

只实现了导出到luatable, 如果想导出到其他语言 修改python代码即可
GitHub项目地址

相关阅读

热门文章

    手机版|MSIPO技术圈 皖ICP备19022944号-2

    Copyright © 2024, msipo.com

    返回顶部