提高游戏开发效率的小工具之配置表生成工具

        游戏开发中,经常会遇见各式各样的配置表,不同的字段,加上不同的类型,组成的策划们所需要的配置表,但为了达到版本内容,往往配置表格式变化反复无穷。因为在经过数个游戏项目的摧残之后,我们总结了一套比较实用的配置表生成工具。基本原理是约定一套excel格式,然后制定多种生成函数的格式,然后根据需要生成指定语言格式的文件模块。

        以下是这套工具的详细约定:

1.目录列表:

2:Configs目录。这里存放的是设置文档 Setting.cfg

{
    "app_set": {},
    "path_set": {
        "erl_path": "E:\\workplace\\erlang_java\\Auto_Data\\Erlang\\data",
        "hrl_path": "E:\\workplace\\erlang_java\\Auto_Data\\Erlang\\include",
        "excel_path": "E:\\workplace\\erlang_java\\Auto_Data\\Excels"
    }
}

3.Erlang目录。这里存放的是生成指定语言格式的文件模块,也可以更换为其他语言格式,或者新建目录,然后格式填写在Setting.cfg中。

4.Excels目录。这里存放的是配置表文件。

 配置表列表

扫描二维码关注公众号,回复: 15561224 查看本文章

 data数据工作表

上图中各行的约定是:

1)第一行为中文注释名

2)第二行为英文翻译名

3)第三行为数据类型,数据类型支持 int、float、string、json

4)第四行为数据引用表与字段,即该字段下数据必须存在与引用表中

5)第五行为前端是否导出,0|不填:导出;1:不导出

6)第六行为后端是否导出,0|不填:导出;1:不导出

config配置工作表

上图中各个字段的约定是:

1)type:生成的语言格式模块。如上图 erl,则会生成  xxx.erl

2)fun_name:生成的函数名

3)keys:函数引用参数字段。需要使用中括号圈起来

4)vals:函数导出参数字段。需要使用中括号圈起来

5.PyPlace目录。这里存放的是python 代码模块。

模块列表 

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 文件名:main.py
# author:zhlhudson

# 这个模块适用于自动编译配置

from csv import excel
from excel_pkg import excel_common
import excel_gui

def main():
    print(dir(excel_common))
    excel_gui.excel_gui_main()
    return

if __name__ == "__main__":
    main()
    pass

主模块

# coding=utf-8
# 文件名:excel_gui.py
# author:zhlhudson

import os
import wx
import re
from excel_pkg import excel_common as ec
import excel_ruler

class excelizer_frame(wx.Frame):
    def __init__(self, maxSizeWeight, maxSizeHeight):
        self.maxSizeWeight = maxSizeWeight
        self.maxSizeHeight = maxSizeHeight
        self.maxSize = (self.maxSizeWeight, self.maxSizeHeight)
        super().__init__(parent=None, title="wxPython", size=self.maxSize)
        self.SetMaxSize(self.maxSize)
        self.SetMinSize(self.maxSize)

# 设置界面
class excelizer_setting(excelizer_frame):
    def __init__(self, parent):
        self.maxSizeWeight = 800
        self.maxSizeHeight = 500
        super().__init__(self.maxSizeWeight, self.maxSizeHeight)
        self.parent = parent
        self.setting = ec.load_setconfig()
        self.set_panel = wx.Panel(self)

        path_set = self.setting['path_set']
        text_size = (self.maxSizeWeight/2, 24)
        btn_size = (120, 24)
        # 按钮坐标偏移量
        btn_x_offset = 20
        for key_index in range(len(path_set.keys())):
            set_key = list(path_set.keys())[key_index]
            btn_path = path_set[set_key]
            self.btn_layout(key_index, set_key, btn_path, text_size, btn_size, btn_x_offset)
        self.Center()

    # 设置按钮布局
    def btn_layout(self, _id, set_key, btn_path, text_size, btn_size, btn_x_offset):
        btn_y = 10 + _id * 30
        path_text = wx.TextCtrl(self.set_panel, id=200+_id, style=wx.TE_LEFT | wx.TE_READONLY,
                                    size=text_size, pos=(10, btn_y))
        path_text.AppendText(set_key + " : " + btn_path)
        erl_path_btn = wx.Button(self.set_panel, id=1000+_id, label=u"修改路径",
                                 size=btn_size, pos=(self.maxSizeWeight / 2 + btn_x_offset, btn_y))
        # lambda 方法增加按钮事件参数
        erl_path_btn.Bind(wx.EVT_BUTTON, lambda e, pt=path_text, sk=set_key: self.btn_event(e, pt, sk))
        pass

    # 按钮事件
    def btn_event(self, event, path_text, set_key):
        print("打印测试。。。。。sss")
        dlg = wx.DirDialog(self, u"选择文件夹", defaultPath=self.setting['path_set'][set_key],
                           style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            self.setting['path_set'][set_key] = dlg.GetPath()
            ec.reset_setconfig(self.setting)
            path_text.Clear()
            path_text.AppendText(set_key + " : " + self.setting['path_set'][set_key])
        dlg.Destroy()
        pass

    def Destroy(self):
        print("销毁设置面板...")
        self.parent.Thaw()
        self.parent.set_frame = None
        super().Destroy()
        return False

# 主界面
class excelizer_main(excelizer_frame):
    def __init__(self):
        self.maxSizeWeight = 1024
        self.maxSizeHeight = 760
        super().__init__(self.maxSizeWeight, self.maxSizeHeight)

        # 菜单栏
        menubar = wx.MenuBar()
        menu_file = wx.Menu()
        menu_set = wx.Menu()
        menu_about = wx.Menu()
        menubar.Append(menu_file, u"菜单")
        menubar.Append(menu_set, u"设置")
        menubar.Append(menu_about, u"关于")
        menu_set.Bind(wx.EVT_MENU_OPEN, self.menu_set)
        menu_about.Bind(wx.EVT_MENU_OPEN, self.menu_about)
        self.set_frame = None
        self.about_frame = None
        self.SetMenuBar(menubar)

        self.panel = wx.Panel(self, -1)
        # 导出按钮
        self.export_btn = wx.Button(parent=self.panel, id=-1, label=u"全导出",
                                    size=(120, 30), pos=(10, 0))
        self.export_btn.Bind(wx.EVT_BUTTON, self.export_event)

        # 搜索框
        self.search_text = wx.TextCtrl(parent=self.panel, id=-1, style=wx.TE_LEFT,
                                       size=(300, 30), pos=(150, 0))
        self.search_text.Bind(wx.EVT_TEXT, self.search_event)

        # 展示列表
        self.check_list = wx.CheckListBox(
            parent=self.panel, id=wx.ID_VIEW_LIST, choices=[], 
            size=(300, self.maxSizeHeight-200), pos=(10, 40))
        self.show_excel_list()

        self.text = wx.TextCtrl(
            parent=self.panel, id=-1, style=wx.TE_MULTILINE|wx.TE_READONLY, 
            size=(self.maxSizeWeight/2, self.maxSizeHeight-200), pos=(400, 40))
        self.Center()

    def menu_about(self, event):
        wx.MessageBox(message=u"zhlhudson 开发设计!", style=wx.OK|wx.CENTER)

    # 设置按钮
    def menu_set(self, event):
        print("打开设置.." + str(self.set_frame == None))
        if self.set_frame == None:
            self.set_frame = excelizer_setting(self)
            self.set_frame.Show()
            self.Freeze()
        self.set_frame.SetFocus()
    
    # 显示配置列表
    def show_excel_list(self):
        all_excels = os.listdir(ec.get_excel_path())  
        all_excels = excel_ruler.filter_valid_files(all_excels)
        self.check_list.Clear()
        self.check_list.InsertItems(all_excels, 0) 
        self.check_list.Bind(wx.EVT_CHECKLISTBOX, self.export_layout)

    # 搜索框事件
    def search_event(self, event):
        search_str = str.strip(self.search_text.GetLineText(0))
        if len(search_str) > 0:
            # 忽略大小写
            all_strs = self.check_list.GetStrings()
            all_checked = []
            for cb in all_strs:
                index_ = self.check_list.FindString(cb)
                result = re.match('(.*)%s(.*)'%(search_str), cb)
                if not result:
                    self.check_list.Delete(index_)
                else:
                    all_checked.append(cb)
            self.check_list.SetCheckedStrings(all_checked)
        else:
            self.show_excel_list()

    # 导出按钮布局
    def export_layout(self, event):
        if len(self.check_list.GetCheckedStrings()) > 0:
            self.export_btn.SetLabel(u"部分导出")
        else:
            self.export_btn.SetLabel(u"全导出")

    # 导出事件
    def export_event(self, event):
        self.text.Clear()
        checked_strs = self.check_list.GetCheckedStrings() != [] and \
            self.check_list.GetCheckedStrings() or self.check_list.GetStrings()
        # 全导出时,将目录下的文件全删除
        if self.export_btn.GetLabelText() == u"全导出":
            def del_file(path_):
                for fn in os.listdir(path_):
                    os.remove(os.path.join(path_, fn))
            del_file(ec.get_erl_path())
            del_file(ec.get_hrl_path())
        # 部分导出,则只删除对应的文件
        else:
            def del_file(path_):
                cns = [cs.split('.')[0] for cs in checked_strs]
                for fn in os.listdir(path_):
                    if cns == []: 
                        break
                    for cn in cns:
                        if not re.match('(.*)%s(.*)'%(cn), fn): continue
                        os.remove(os.path.join(path_, fn))
                        cns.remove(cn)
                        break
            del_file(ec.get_erl_path())
            del_file(ec.get_hrl_path())
        excel_ruler.batch_make_file(checked_strs)

def excel_gui_main():
    app = wx.App()
    frame = excelizer_main()
    frame.Show()
    app.MainLoop()

if __name__ == "__main__":
    app = wx.App()
    frame = excelizer_main()
    frame.Show()
    app.MainLoop()

小工具面板模块

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 文件名:excel_ruler.py
# author:zhlhudson

# 配置表规则模块
# (1)读取规则
#      第1行 :字段中文命名
#      第2行 :字段英文命名
#      第3行 :字段类型
#          int :整型
#          float :浮点型
#          string :字符串
#          json :json类型([{"attr":1,"rate":100,"name":"生命"}])
#      第4行 :字段引用行(ref:scene:id)
#      第5行 :前端是否导出(0|不填:导出;1:不导出)
#      第6行 :后端是否导出(0|不填:导出;1:不导出)
# (2)转译规则
#      第3行 :字段类型
#          int、float、string :与常用规则类似
#          json :需要转化为对应erlang map格式
#      第4行 :字段引用行。需要对比引用配置表,查看字段是否存在

import xlrd
import os
import json
from excel_pkg.excel_common import excel_common
from excel_pkg import excel_common as ec

# 配置表文件读写类
class excel_filelizer(excel_common):
    _instance = None
    def __init__(self, filename):
        print("声明。。。。。")
        self.filename = filename
        # 打开文件字典
        self.open_file_dict = {}

    def __del__(self):
        print("删除。。。。。")
        # 打开文件字典
        for open_filename in self.open_file_dict.keys():
            self.close_file(open_filename)
        self.open_file_dict = None

    # 单例模式
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance

    # 打开文件
    def open_file(self, open_filename):
        if not open_filename in self.open_file_dict.keys():
            # TODO : 生成文件名不大对
            # 后缀名不是xlsx和xls忽略
            suffix_name = (open_filename.split('.'))[-1]
            file_path = os.path.dirname(__file__)
            if suffix_name == self.cfg_type_erl():
                file_path = os.path.join(ec.get_erl_path(), open_filename)
            elif suffix_name == self.cfg_type_hrl():
                file_path = os.path.join(ec.get_hrl_path(), open_filename)
            fd_ = open(file_path, 'a+', encoding='utf8')
            self.open_file_dict[open_filename] = fd_
        return self.open_file_dict[open_filename]

    # 关闭文件
    def close_file(self, open_filename):
        if open_filename in self.open_file_dict.keys():
            self.open_file_dict[open_filename].close()
            self.open_file_dict.pop(open_filename)

    # 回写文件
    def write_file(self, open_filename, str_list):
        fd_ = self.open_file(open_filename)
        fd_.writelines(str_list)
        fd_.flush()
        self.close_file(open_filename)

    # 读取文件
    def read_file(self, open_filename):
        fd_ = self.open_file(open_filename)
        fd_.readlines()

# 配置表规则模块
class excel_ruler(excel_common):
    def __init__(self, filename):
        # 当前定位的文件
        self.filename = filename

    def __del__(self):
        print("释放%s资源" % self.__class__.__name__)
        pass

    def set_setting_dict(self, setting_dict):
        self.setting_dict = setting_dict
        pass

    # 处理配置工作表
    def deal_sheet(self, excel):
        if (self.data_name() in excel.sheet_names()) and (self.cfg_name() in excel.sheet_names()):
            data_sheet = excel.sheet_by_name(self.data_name())
            cfg_sheet = excel.sheet_by_name(self.cfg_name())
            cfg_dict_list = self.deal_config_sheet(cfg_sheet, data_sheet)
            if cfg_dict_list == False:
                return False
            if not self.deal_data_sheet(data_sheet):
                return False

            has_record = False # 是否声明record
            for cfg_dict in cfg_dict_list:
                if cfg_dict[self.cfg_type()] == self.cfg_type_hrl():
                    self.format_define_hrl(cfg_dict, data_sheet)
                if cfg_dict[self.cfg_type()] == self.cfg_type_erl():
                    if not has_record:
                        has_record = True
                        self.format_record_hrl(data_sheet)
                        self.format_include_erl()
                    self.format_erl(cfg_dict, data_sheet)
        return True

    # 处理数据格式工作表
    def deal_data_sheet(self, data_sheet):
        for rid in range(data_sheet.nrows):
            # 第1行 :字段备注
            if rid == self.cn_name_rid(): continue
            # 剩下的字段不需要检测
            if rid > self.pr_ref_rid(): break
            if not self.is_valid_of_data_value(rid, data_sheet): return False
        return True

    # 检测数据工作表所有参数是否有效
    def is_valid_of_data_value(self, rid, data_sheet):
        # 第2行 :字段英文命名
        if rid == self.en_name_rid():
            can_pass = True
            for cid in range(data_sheet.ncols):
                en_name = data_sheet.cell_value(rid, cid)
                if en_name != "" and not en_name.islower():
                    print("%s data 工作表中第%s行%s列 %s,字段英文名须全部小写..." %
                          (self.filename, str(rid + 1), str(cid + 1), str(en_name)))
                    can_pass = False
                    break
        # 第3行 :字段类型
        elif rid == self.pr_type_rid():
            can_pass = True
            for cid in range(data_sheet.ncols):
                pr_type = data_sheet.cell_value(rid, cid)
                if pr_type != "" and not str.islower(pr_type):
                    print("%s data 工作表中第%s行%s列 %s,字段类型须全部小写..." %
                          (self.filename, str(rid + 1), str(cid + 1), str(pr_type)))
                    can_pass = False
                    break
                if pr_type != "" and not pr_type in self.param_types():
                    print("%s data 工作表中第%s行%s列 %s,字段类型暂不支持..." %
                          (self.filename, str(rid + 1), str(cid + 1), str(pr_type)))
                    can_pass = False
                    break
        # 第4行 :字段引用行(ref:scene:id)
        elif rid == self.pr_ref_rid():
            can_pass = True
            for cid in range(data_sheet.ncols):
                pr_ref = data_sheet.cell_value(rid, cid)
                if pr_ref != "" and not str.islower(pr_ref):
                    print("%s data 工作表中第%s行%s列 %s,字段引用行须全部小写..." %
                          (self.filename, str(rid + 1), str(cid + 1), str(pr_ref)))
                    can_pass = False
                    break
                if pr_ref != "" and len(pr_ref.split(':')) != self.pr_ref_count():
                    print("%s data 工作表中第%s行%s列 %s,字段引用行格式有误..." %
                          (self.filename, str(rid + 1), str(cid + 1), str(pr_ref)))
                    can_pass = False
                    break
                if pr_ref != "":
                    can_pass = self.is_valid_of_param_ref(pr_ref, cid, data_sheet.col_values(cid))
                    if not can_pass : break
        else : can_pass = True
        return  can_pass

    # 判断引用表里是否存在字段
    def is_valid_of_param_ref(self, pr_ref, cid, data_col_list):
        [_, _filename, _param_name] = pr_ref.split(':')
        file_path = os.path.join(ec.get_excel_path(), _filename)
        can_pass = True
        is_xlsx = os.path.exists(file_path + ".xlsx")
        is_xls = os.path.exists(file_path + ".xls")
        if not is_xlsx and not is_xls:
            return False
        # 判断引用表里是否存在字段
        elif is_xlsx: file_path += ".xlsx"
        else: file_path += ".xls"
        excel = xlrd.open_workbook(file_path, encoding_override="utf-8")
        ref_sheet = excel.sheet_by_name(self.data_name())
        ref_en_name_list = ref_sheet.row_values(self.en_name_rid())
        if not _param_name in ref_en_name_list:
            return False
        ref_col_list = ref_sheet.col_values(ref_en_name_list.index(_param_name))
        # 遍历引用数据是否都存在与引用表内
        for rid in range(len(data_col_list)):
            if rid <= 5: continue
            if data_col_list[rid] in ref_col_list: continue
            else:
                print("%s data 工作表中第%s行%s列 %s,字段引用行引用的数据不存在..." %
                      (self.filename, str(rid + 1), str(cid + 1), str(data_col_list[rid])))
                can_pass = False
                break
        excel.release_resources()
        return can_pass

    # 处理配置格式工作表
    def deal_config_sheet(self, cfg_sheet, data_sheet):
        cfg_dict_list = []
        for rid in range(cfg_sheet.nrows):
            cfg_dict = json.loads(cfg_sheet.row_values(rid)[0])
            if not self.is_valid_of_config_value(cfg_dict, data_sheet):
                return False
            cfg_dict_list.append(cfg_dict)
        return cfg_dict_list

    # 检测配置工作表所有参数是否存在
    def is_valid_of_config_value(self, cfg_dict, data_sheet):
        # 没有包含类型
        if not self.cfg_type() in cfg_dict.keys():
            return False
        cfg_type = cfg_dict[self.cfg_type()]
        # 没有包含函数名
        if cfg_type == self.cfg_type_erl() and not self.fun_name() in cfg_dict.keys():
            return False
        en_names = data_sheet.row_values(self.en_name_rid())
        # 返回值为全部时,只需要检测参数列
        key_vals = cfg_dict[self.vals()] != self.val_all() and \
                   cfg_dict[self.keys()] + cfg_dict[self.vals()] or cfg_dict[self.keys()]
        for _kv_ in key_vals:
            if _kv_ not in en_names:
                print("%s config 工作表中%s参数不存在..." % (self.filename, _kv_))
                return False
            pr_type = data_sheet.cell_value(self.pr_type_rid(), en_names.index(_kv_))
            if pr_type != "" and not str.islower(pr_type):
                print("%s config 工作表中%s参数,字段类型须全部小写..." % (self.filename, str(pr_type)))
                return False
            elif pr_type != "" and not pr_type in self.param_types():
                print("%s config 工作表中%s参数,字段类型暂不支持..." % (self.filename, str(pr_type)))
                return False
            elif _kv_ in cfg_dict[self.keys()] and cfg_type == self.cfg_type_hrl() and \
                    (not len(cfg_dict[self.keys()]) == 1 or len(cfg_dict[self.vals()]) < 1):
                print("%s config 工作表中%s参数数量非法..." % (self.filename, str(_kv_)))
                return False
            elif _kv_ in cfg_dict[self.keys()] and cfg_type == self.cfg_type_hrl() and \
                    not self.key_hrl_valid_pr_types(pr_type):
                print("%s config 工作表中%s参数类型须为%s..." %
                      (self.filename, str(_kv_), str(self.get_key_hrl_valid_pr_types())))
                return False
            elif _kv_ in cfg_dict[self.keys()] and cfg_type == self.cfg_type_erl() and \
                    not self.key_erl_valid_pr_types(pr_type):
                print("%s config 工作表中%s参数类型须为%s..." %
                      (self.filename, str(_kv_), str(self.get_key_erl_valid_pr_types())))
                return False
        return True

    # 组织文件格式 - 头文件
    # -define(XXX_YYY, aaa).
    def format_define_hrl(self, cfg_dict, data_sheet):
        cfg_keys = cfg_dict[self.keys()]
        cfg_vals = cfg_dict[self.vals()]
        cfg_key = cfg_keys[0]
        en_names = data_sheet.row_values(self.en_name_rid())
        # key 列id
        key_cid = en_names.index(cfg_key)
        key_pr_type = data_sheet.cell_value(self.pr_type_rid(), key_cid)
        # vals 列id
        val_cids = {}
        for val in cfg_vals:
            val_cid = en_names.index(val)
            val_pr_type = data_sheet.cell_value(self.pr_type_rid(), val_cid)
            val_cids[val_cid] = val_pr_type
        # 得到真实文件名
        (realy_filename, _) = os.path.splitext(self.filename)
        # 逐行拼接字符串
        hrl_str_list = []
        for rid in range(data_sheet.nrows):
            if rid <= self.server_output_rid(): continue
            # key 拼接结果
            key_ret = self.format_ret(key_pr_type, data_sheet.cell_value(rid, key_cid))
            key_str = ('%s_%s' % (realy_filename, key_ret)).upper()
            # val 拼接结果
            val_list = []
            for val_cid in val_cids.keys():
                val_ret = self.format_ret(val_cids[val_cid], data_sheet.cell_value(rid, val_cid))
                val_list.append(val_ret)
            if len(cfg_vals) > 1:
                val_str = '[%s]' % (','.join(val_list))
            else:
                val_str = val_list[0]
            hrl_str_list.append(u'-define(%s, %s).\n' % (key_str, val_str))
        if len(hrl_str_list) > 0:
            filelizer = excel_filelizer(self.filename)
            filelizer.write_file('cfg_' + realy_filename + '.' + self.cfg_type_hrl(), hrl_str_list)
        pass

    # 组织文件格式 - 头文件
    # -record(xxx, {}).
    def format_record_hrl(self, data_sheet):
        # 字段拼接列表
        pr_str_list = []
        for cid in range(data_sheet.ncols):
            # 不导出字段 | 沒有命名 | 字段类型,跳过
            if data_sheet.cell_value(self.server_output_rid(), cid) == 1 or \
                    data_sheet.cell_value(self.en_name_rid(), cid) == "" or \
                    data_sheet.cell_value(self.pr_type_rid(), cid) == "":
                continue
            en_name = data_sheet.cell_value(self.en_name_rid(), cid)
            pr_type = data_sheet.cell_value(self.pr_type_rid(), cid)
            pr_str_list.append('%s = %s' % (en_name, self.format_ret(pr_type)))
        if len(pr_str_list) > 0:
            # 得到真实文件名
            (realy_filename, _) = os.path.splitext(self.filename)
            hrl_str = u'-record(%s, {\n\t%s\n}).\n' % ('cfg_' + realy_filename, ',\n\t'.join(pr_str_list))
            filelizer = excel_filelizer(self.filename)
            filelizer.write_file('cfg_' + realy_filename + '.' + self.cfg_type_hrl(), [hrl_str])
        pass

    # 组织文件格式 - 功能模块
    # erl功能模块 include
    def format_include_erl(self):
        # 得到真实文件名
        (realy_filename, _) = os.path.splitext(self.filename)
        include_str = '-module(cfg_{0}).\n' \
                      '-include("cfg_{0}.{1}").\n' \
                      '-compile(export_all).\n'.format(realy_filename, self.cfg_type_erl())
        filelizer = excel_filelizer(self.filename)
        filelizer.write_file('cfg_' + realy_filename + '.' + self.cfg_type_erl(), include_str)
        pass

    # 组织文件格式 - 功能模块和头文件
    def format_erl(self, cfg_dict, data_sheet):
        fun_name = cfg_dict[self.fun_name()]
        cfg_keys = cfg_dict[self.keys()]
        cfg_vals = cfg_dict[self.vals()]
        en_names = data_sheet.row_values(self.en_name_rid())
        def sub_kv_cids(cfg_kvs):
            _cids = {}
            for _kv_ in cfg_kvs:
                _cid = en_names.index(_kv_)
                _pr_type = data_sheet.cell_value(self.pr_type_rid(), _cid)
                _cids[_cid] = _pr_type
            return _cids
        # keys 列id
        key_cids = sub_kv_cids(cfg_keys)
        # vals 列id
        val_cids = {}
        if not cfg_vals == self.val_all():
            val_cids = sub_kv_cids(cfg_vals)
        # 得到真实文件名
        (realy_filename, _) = os.path.splitext(self.filename)
        # 逐行拼接字符串
        hrl_str_list = []
        for rid in range(data_sheet.nrows):
            if rid <= self.server_output_rid(): continue
            def sub_format(kv_cids):
                # key 拼接结果
                kvlist = []
                for kv_cid in kv_cids.keys():
                    kv_ret = self.format_ret(kv_cids[kv_cid], data_sheet.cell_value(rid, kv_cid))
                    kvlist.append(kv_ret)
                return kvlist
            # key 拼接结果
            key_list = sub_format(key_cids)
            key_str = ','.join(key_list)
            # val 拼接结果
            if not cfg_vals == self.val_all() and len(val_cids) > 1:
                val_list = sub_format(val_cids)
                val_str = u'[%s]' % (','.join(val_list))
            elif not cfg_vals == self.val_all():
                val_list = sub_format(val_cids)
                val_str = val_list[0]
            else:
                # 字段拼接列表
                pr_str_list = []
                for cid in range(data_sheet.ncols):
                    # 不导出字段 | 沒有命名 | 字段类型,跳过
                    if data_sheet.cell_value(self.server_output_rid(), cid) == 1 or \
                            data_sheet.cell_value(self.en_name_rid(), cid) == "" or \
                            data_sheet.cell_value(self.pr_type_rid(), cid) == "":
                        continue
                    en_name = data_sheet.cell_value(self.en_name_rid(), cid)
                    pr_type = data_sheet.cell_value(self.pr_type_rid(), cid)
                    pr_val = data_sheet.cell_value(rid, cid)
                    pr_str_list.append('%s = %s' % (en_name, self.format_ret(pr_type, pr_val)))
                val_str = u'#%s{%s}.' % ('cfg_' + realy_filename, ','.join(pr_str_list))
            hrl_str_list.append(u'%s(%s) -> %s.\n' % (fun_name, key_str, val_str))
        filelizer = excel_filelizer(self.filename)
        filelizer.write_file('cfg_' + realy_filename + '.' + self.cfg_type_erl(), hrl_str_list)
        pass

# erlang目录
ErlangPath = r'..\\Erlang\\'

# 过滤有效配置表
def filter_valid_files(filenames):
    valid_names = []
    for filename in filenames:
        print(filename)
        # 预览文件直接忽略
        if filename[0:1] == '~':
            continue
        # 后缀名不是xlsx和xls忽略
        suffix_name = (filename.split('.'))[-1]
        if suffix_name != 'xlsx' and suffix_name != 'xls':
            continue
        valid_names.append(filename)
    return valid_names

# 批量导出配置文件
def batch_make_file(valid_names):
    for filename in valid_names:
        exceler = excel_ruler(filename)
        file_path = os.path.join(ec.get_excel_path(), filename)
        excel = xlrd.open_workbook(file_path, encoding_override="utf-8")
        exceler.deal_sheet(excel)
        excel.release_resources()
        print(r"释放配置表读取资源...")

def __main__():
    pass

if __name__ == "__main__":
    __main__()
    # TODO : 测试读写大excel效率
    # TODO : 多线程
    # TODO : 界面

小工具规则模块

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 文件名:excel_common.py
# author:zhlhudson

import json
import os

# 配置表常用类
class excel_common(object):
    _instance = None
    def __init__(self):
        pass

    def __del__(self):
        print(r"释放excel_common资源...")
        pass

    # 单例模式
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance

    def data_name(self):
        # 配置内容工作表
        return 'data'

    def cfg_name(self):
        # 配置格式工作表
        return 'config'

    def cfg_type(self):
        # cfg生成类型
        return "type"

    def cfg_type_hrl(self):
        # cfg生成文件 只有头文件
        return "hrl"

    def cfg_type_erl(self):
        # cfg生成文件 功能模块和头文件
        return "erl"

    def fun_name(self):
        # cfg生成函数名
        return "fun_name"

    def keys(self):
        # cfg生成函数参数
        return "keys"

    # 只有头文件
    def get_key_hrl_valid_pr_types(self):
        # cfg生成函数参数 允许的格式
        return ['int', 'string']

    def key_hrl_valid_pr_types(self, key_type):
        # cfg生成函数参数 允许的格式
        if key_type in self.get_key_hrl_valid_pr_types(): return True
        return False

    # 有头文件和模块文件
    def get_key_erl_valid_pr_types(self):
        # cfg生成函数参数 允许的格式
        return ['int', 'float', 'string']

    def key_erl_valid_pr_types(self, key_type):
        # cfg生成函数参数 允许的格式
        if key_type in self.get_key_erl_valid_pr_types(): return True
        return False

    def vals(self):
        # cfg生成函数返回值
        return "vals"

    def val_all(self):
        # cfg生成函数返回值
        return "all"

    def param_types(self):
        # 配置表字段类型
        return ['int', 'float', 'string', 'json']

    def cn_name_rid(self):
        # 第1行 :字段备注
        return 0

    def en_name_rid(self):
        # 第2行 :字段英文命名
        return 1

    def pr_type_rid(self):
        # 第3行 :字段类型
        return 2

    def pr_ref_rid(self):
        # 第4行 :字段引用行(ref:scene:id)
        return 3

    def pr_ref_count(self):
        # 配置表引用字段拆分长度
        return 3

    def client_output_rid(self):
        # 第5行 :前端是否导出(0|不填:导出;1:不导出)
        return 4

    def server_output_rid(self):
        # 第6行 :后端是否导出(0|不填:导出;1:不导出)
        return 5

    # 格式化
    # pr_type :字段格式
    # val : 格式化目标
    def format_ret(self, pr_type, val=None):
        # 返回 cfg生成函数参数 返回值 允许的格式
        if pr_type == 'int' and val == None: return str('%d' % 0)
        if pr_type == 'int': return str('%d' % val)
        if pr_type == 'float' and val == None: return str('%.3f' % 0)
        if pr_type == 'float': return str('%.3f' % val)
        if pr_type == 'string' and val == None: return '\"\"'
        if pr_type == 'string': return u'\"%s\"' % val
        if pr_type == 'json' and val == None: return '[]'
        if pr_type == 'json':
            # 闭包 转化 json格式为erl map格式
            def val_json_format(v_dict):
                v_ret = []
                for k in v_dict.keys():
                    v_ret.append('%s => %s' % (str(k), str(v_dict[k])))
                return '#{%s}' % (','.join(v_ret))
            val_dict = json.loads(val)
            if isinstance(val_dict, list):
                val_ret = []
                for v_dict in val_dict:
                    val_ret.append(val_json_format(v_dict))
                return '[%s]' % (','.join(val_ret))
            else:
                return val_json_format(val_dict)

# 加载配置文件
def load_setconfig():
    with open(u"..\\..\\Configs\\Setting.cfg", mode="r+", encoding='utf-8') as fd_:
        setting = json.load(fd_)
        fd_.close()
        return setting

# 重置配置文件
def reset_setconfig(setting):
    with open(r"..\\..\\Configs\\Setting.cfg", mode="w+", encoding='utf-8') as fd_:
        json.dump(setting, fd_, indent=4)
        fd_.close()

# 获取配置表生成文件路径-hrl
def get_hrl_path():
    return load_setconfig()['path_set']['hrl_path']

# 获取配置表生成文件路径-erl
def get_erl_path():
    return load_setconfig()['path_set']['erl_path']

# 获取配置表路径
def get_excel_path():
    return load_setconfig()['path_set']['excel_path']

if __name__ == "__main__":
    pass

小工具常用函数

6.小工具实际使用效果

 可以具备模糊搜索查找(用的是正则表达式,可能效率有点差,但是书写方便),支持全导出或者部分导出,导出结果之后会打印在右边的文档框内。


以上是这个配置表一个详细内容,里面有很多不足,希望大佬斧正,同时也希望对各位学习中、甚至项目开发中有所帮助。欢迎一起探讨python、erlang甚至别的语言。

当然上面的小工具还没有完善,其实实际项目中所导出的配置表文件可能多达几百份甚至上千份,这时候单线程导出就有点看不上了,所以这里有兴趣的可以写成支持多线程的。

猜你喜欢

转载自blog.csdn.net/qq_15855921/article/details/124676967