Configuration table generation tool for small tools that improve game development efficiency

        In game development, we often encounter a variety of configuration tables, different fields, and different types to form the configuration tables needed by the planners. However, in order to achieve the version content, the configuration table format often changes endlessly. Because after the destruction of several game projects, we have summarized a set of more practical configuration table generation tools. The basic principle is to agree on a set of excel formats, and then formulate a variety of formats for generating functions, and then generate file modules in specified language formats as needed.

        The following are the detailed conventions of this set of tools:

1. Directory listing:

2: Configs directory. Stored here is the setting file  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 directory. Stored here is the file module that generates the specified language format, and can also be replaced with other language formats, or create a new directory, and then fill in the format in Setting.cfg.

4. Excels directory. The configuration table file is stored here.

 configuration table list

 data data sheet

The conventions for the lines in the figure above are:

1) The first line is the Chinese comment name

2) The second line is the English translation name

3) The third line is the data type, the data type supports int, float, string, json

4) The fourth line is the data reference table and field, that is, the data under this field must exist in the reference table

5) The fifth line is whether the front end is exported, 0 | blank: export; 1: not export

6) The sixth line is whether the backend is exported, 0 | blank: export; 1: not export

config configuration worksheet

The conventions of the fields in the above figure are:

1) type: the generated language format module. As shown above erl, xxx.erl will be generated

2) fun_name: the generated function name

3) keys: function reference parameter field. need to be enclosed in square brackets

4) vals: function export parameter field. need to be enclosed in square brackets

5. The PyPlace directory. Stored here are python code modules.

module list 

#!/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

main module

# 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()

Widget Panel Module

#!/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 : 界面

Gadget Rules Module

#!/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

Gadget Common Functions

6. The actual use effect of gadgets

 It can have fuzzy search and lookup ( regular expressions are used , which may be a bit inefficient, but it is easy to write), supports full or partial export, and the exported results will be printed in the document box on the right.


The above is a detailed content of this configuration table. There are many deficiencies in it. I hope that you can correct it. At the same time, I also hope that it will be helpful to everyone in your study and even in project development. Welcome to discuss python, erlang or even other languages.

Of course, the above small tools are not yet perfect. In fact, the configuration table files exported in the actual project may be as many as hundreds or even thousands of copies. At this time, single-threaded export is a bit despised, so if you are interested here, you can write it as support. multi-threaded.

Guess you like

Origin blog.csdn.net/qq_15855921/article/details/124676967