Unity Excel转Json编辑器工具

功能说明:根据 .xlsx 文件生成对应的 JSON 文件,并自动创建脚本

注意事项

  1. Excel 读取依赖
    本功能依赖 EPPlus 库,只能读取 .xlsx 文件。请确保将该脚本放置在 Assets 目录下的 Editor 文件夹中。同时,在 Editor 下再创建一个 Excel 目录,并将你的 .xlsx 文件放到 Excel 目录下。注意:该目录下只能有一个 .xlsx 文件,且该文件是唯一的数据源。

    • Excel 文件格式要求
      • 第一行:字段名(与自动生成脚本中的字段对应)。
      • 第二行:中文注释。
      • 第三行:字段的数据类型(目前支持 intfloatdoublestringbool 和数组类型,如 int[]string[])。
      • 第四行开始:实际数据。
    • Epplus依赖获取查看我的另一篇文章Nuget For Unity插件介绍_nugetforunity-CSDN博客

 

  1. 生成脚本与 JSON 文件
    使用编辑器中的 ExcelTool 进行生成,点击 读取 Excel 按钮后,将自动执行以下操作:

    • 删除之前生成的脚本目录和 JSON 目录(如果存在),然后重新生成它们。
    • 注意:在这两个目录下请不要放置其他文件,因为此工具会在每次生成时覆盖这些目录。
  2. 关于数组格式
    数组数据需要按如下格式写入:
    例如1|2|3。数组成员使用 | 分隔。

  3. 支持多 sheet
    一个 .xlsx 文件中可以包含多个 sheet。在读取时,工具会读取所有 sheet 数据。请注意:

    • 将每个 sheet 的名字改为与要生成的脚本名一致。
    • Sheet 名称必须符合 C# 的命名规范,建议使用 TB_ 开头。

提示

  • 脚本命名:请确保每个 sheet 的名字与生成的 C# 脚本的名称一致。
  • 字段类型:当前支持的字段类型包括基本数据类型(intfloatdoublestringbool)以及数组类型(如 int[]string[])。
  • 感谢原作者:特别感谢原作者“小人”的贡献,我仅添加了一些功能,以下是他在 B站的教程视频地址:Unity中简单根据excel文件自动生成对应的C#脚本及json文件_哔哩哔哩_bilibili

格式

1f84954687904290b9d376aa79ce3845.png

保证这个目录格式

3afd64d1e4a9491189906f9d9d3850f6.png

Excel格式

 

源码

using OfficeOpenXml;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using System;
using UnityEditor;
using UnityEngine;

/*

功能:根据.xlsx文件生成对应的json文件,并自动创建脚本

注意:

   一 Excel读取依赖EPPlus,只能读.xlsx文件,Asset下创建一个Editor,同时将该脚本放到Editor下
      然后在Editor下再创建一个Excel目录,然后将你的Excel文件放到Excel目录下,注意Excel目录下
      只能有一个Excel文件,同时Excel格式要符合下列要求,最后Excel是唯一的数据源,所以除了保护好
      你的Excel文件外,其他的可以重新生成.使用编辑器上的ExcelTool/读取Excel按钮生成Json和脚本
      使用该按钮会删除脚本目录和json目录然后重新生成(如果已经生成过),所以不要在这两个目录下
      放置其他文件.

   二 xlsx第一行为英文字段与自动生成脚本中的字段对应

      第二行为中文注释

      第三行为字段的数据类型,目前支持int float double string bool 数组

      数组的写法统一为基本数据类型+[] 如int[] 、string[]

      第四行开始为实际数据

   三 xlsx文件中可以有很多sheet.读取时会读取xlsx的全部sheet

      要将对应的sheet的名字改为与要生成的脚本名一致,所以sheet名要符合C#的命名规范,建议使用TB_开头

   四 数组的书写格式形如:1|2|3,数组成员使用|分隔

   五 感谢原作者小人,我仅做了一些功能补充,下面的地址是小人的b站视频地址
    
*/
[HelpURL("https://www.bilibili.com/video/BV16f421Q7zA/?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click&vd_source=f9b5906b25cd5ca40ec79f317993905b")]
public class ExcelTool
{

    //命名空间列表
    private static List<string> nameSpaceList = new List<string>()
        { "using System;", "[Serializable]"};
    //Root目录,包含Excel本身,Excel生成的json和脚本
    private static readonly string excel = Application.dataPath + "/Editor/Excel";
    //Excel文件
    private static string excelFilePath = excel;
    //脚本目录
    private static readonly string scriptsFolder = excel + "/ExcelScripts";
    //json目录
    private static string jsonFolder = excel + "/Json";

    [MenuItem("ExcelTool/读取Excel")]
    public static void TestTool()
    {


        // 获取目录下所有以 .xlsx 结尾的文件(不包括子目录中的文件)
        string[] files = Directory.GetFiles(excel, "*.xlsx");
        if (files.Length > 0)
        {
            // 获取第一个文件的完整路径
            string firstFilePath = files[0];

            // 获取文件名(不包括路径)
            string fileName = Path.GetFileName(firstFilePath);
            excelFilePath = excelFilePath + "/" + fileName;
        }
        if (!File.Exists(excelFilePath))
        {
            Debug.LogError("excel文件不存在");
            return;
        }

        CreateDirectory(scriptsFolder);
        CreateDirectory(jsonFolder);
        var res = ReadExcel(excelFilePath);
        for (int i = 0; i < res.Count; i++)
        {
            string path = scriptsFolder + "/" + res[i].scriptName + ".cs";
            CreateAScript(path, res[i].scriptName, nameSpaceList, res[i].fieldType, res[i].fieldName);
            CreateAJson(res[i].scriptName, res[i].fieldType, res[i].fieldName, res[i].dataDic);
        }



        AssetDatabase.Refresh();
    }

    private static void CreateDirectory(string path)
    {
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
        else
        {
            path = ConvertToRelativePath(path);
            var b = AssetDatabase.DeleteAsset(path);
            Directory.CreateDirectory(path);
        }
    }
    // 将绝对路径转为相对路径
    private static string ConvertToRelativePath(string absolutePath)
    {
        // 获取项目的 'Assets' 文件夹路径
        string assetsPath = Application.dataPath;

        // 确保返回的路径是相对于 'Assets' 文件夹的
        if (absolutePath.StartsWith(assetsPath))
        {
            // 去掉 Application.dataPath 前缀,返回相对路径
            return "Assets" + absolutePath.Substring(assetsPath.Length);
        }
        Debug.LogError("路径不在 Assets 目录内: " + absolutePath);
        return absolutePath;
    }


    /// <summary>
    /// 读取 .xlsx文件,获取第一张sheet的内容
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static List<(string scriptName, List<string> fieldType, List<string> fieldName, Dictionary<int, List<string>> dataDic)>
       ReadExcel(string path)
    {
        int sheetsCount;
        var list = new List<(string scriptName, List<string> fieldType, List<string> fieldName, Dictionary<int, List<string>> dataDic)>();


        FileInfo fileInfo = new FileInfo(path);
        using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
        {
            sheetsCount = excelPackage.Workbook.Worksheets.Count;
        }

        for (int z = 0; z < sheetsCount; z++)
        {
            //生成的脚本名
            string scriptName;
            //字段类型列表
            List<string> fieldType = new List<string>();
            //字段名列表
            List<string> fieldName = new List<string>();
            //.xlsx除注释行之外的相关数据
            Dictionary<int, List<string>> dataDic = new Dictionary<int, List<string>>();

            using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
            {
                //取得.xlsx中的第一张sheet(EPPlus中下标从1或者0开始,取决于版本)
                ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[z];
                if (worksheet == null)
                {
                    sheetsCount++;
                    continue;
                }

                //取sheet的名字,即生成的脚本名
                scriptName = worksheet.Name;

                //取英文字段名
                //遍历表格第一行取字段名 注意索引下标
                for (int i = 1; i <= worksheet.Dimension.End.Column; i++)
                {
                    if (worksheet.Cells[1, i].Value is null)
                    {
                        Debug.LogError($"当前{worksheet}中第1行第{i}个单元格数据为空");
                        return null;
                    }
                    string field = worksheet.Cells[1, i].Value.ToString();
                    fieldName.Add(field);
                }

                //取字段类型
                //遍历第三行 同上
                for (int i = 1; i <= worksheet.Dimension.End.Column; i++)
                {
                    if (worksheet.Cells[3, i].Value is null)
                    {
                        Debug.LogError($"当前{worksheet}中第3行第{i}个单元格数据为空");
                        return null;
                    }
                    string field = worksheet.Cells[3, i].Value.ToString();
                    fieldType.Add(field);
                }

                //取实际数据

                for (int k = 4; k <= worksheet.Dimension.End.Row; k++)
                {
                    List<string> realData = new List<string>();
                    for (int j = 1; j <= worksheet.Dimension.End.Column; j++)
                    {
                        if (worksheet.Cells[k, j].Value is null)
                        {
                            Debug.LogError($"当前{worksheet}中第{k}行第{j}个单元格数据为空");
                            return null;
                        }

                        string data = worksheet.Cells[k, j].Value.ToString();
                        realData.Add(data);
                    }

                    dataDic[k] = realData;
                }
            }
            list.Add((scriptName, fieldType, fieldName, dataDic));

        }


        return list;
    }


    /// <summary>
    /// 判断字符串列表中是否包含重复成员,有,返回true
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    private static bool HasRepeatedMember(List<string> list)
    {
        //往HaseSet中添加字符串,若不成功添加,说明有重复字符串 
        HashSet<string> hashSet = new HashSet<string>();
        for (int i = 0; i < list.Count; i++)
        {
            if (!hashSet.Add(list[i]))
            {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// 创建一个C#脚本
    /// </summary>
    /// <param name="path">脚本保存路径</param>
    /// <param name="scriptName">脚本名</param>
    /// <param name="nameSpaceList">命名空间列表</param>
    /// <param name="fieldType">字段类型列表</param>
    /// <param name="fieldName">字段名列表</param>
    private static void CreateAScript(string path, string scriptName, List<string> nameSpaceList,
        List<string> fieldType, List<string> fieldName)
    {
        #region 安全校验
        if (fieldType is null || fieldType.Count == 0)
        {
            Debug.LogError($"{scriptName}字段类型列表错误");
            return;
        }
        if (fieldName is null || fieldName.Count == 0)
        {
            Debug.LogError($"{scriptName}字段名列表错误");
            return;
        }
        if (nameSpaceList is null || nameSpaceList.Count == 0)
        {
            Debug.LogError($"{scriptName}命名空间列表错误");
            return;
        }
        if (fieldType.Count != fieldName.Count)
        {
            Debug.LogError($"{scriptName}字段类型列表与字段名列表长度不一致");
            return;
        }
        //生成的字段以字母开头
        for (int i = 0; i < fieldName.Count; i++)
        {
            if (!Regex.IsMatch(fieldName[i], @"^[a-zA-Z_]"))
            {
                Debug.LogError($"{scriptName}中字段名应以字母开头");
                return;
            }
        }
        //避免生成字段重复
        if (HasRepeatedMember(fieldName))
        {
            Debug.LogError($"{scriptName}中出现重复字段");
            return;
        }
        #endregion

        using (StreamWriter writer = new StreamWriter(path))
        {
            //写入命名空间
            for (int i = 0; i < nameSpaceList.Count; i++)
            {
                writer.WriteLine(nameSpaceList[i]);
            }
            //写入脚本名
            writer.WriteLine($"public class {scriptName}");

            writer.WriteLine("{");

            //写入类型及字段
            for (int i = 0; i < fieldName.Count; i++)
            {
                writer.WriteLine($"public {fieldType[i]} {fieldName[i]} ;");
            }

            writer.WriteLine("}");
        }
    }

    /// <summary>
    /// 创建json文件
    /// </summary>
    /// <param name="jsonName">json文件名</param>;
    /// <param name="fieldType">字段类型列表</param>
    /// <param name="fieldName">字段名列表</param>
    /// <param name="dataDic">实际数据字典</param>
    private static void CreateAJson(string jsonName, List<string> fieldType, List<string> fieldName, Dictionary<int, List<string>> dataDic)
    {

        //写一行数据
        StringBuilder sb = new StringBuilder();
        sb.Append("[\n");


        for (int i = 4; i < dataDic.Count + 4; i++)
        {
            //写一行 追加
            string s = GetALine(fieldType, fieldName, dataDic[i]);
            sb.Append(s);
            //不是最后一项数据,加逗号
            if (i != dataDic.Count + 3)
            {
                sb.Append(",");
            }

            //换行
            sb.Append("\n");
        }

        //写最后一个括号
        sb.Append("]\n");

        string path = jsonFolder + "/" + jsonName + ".json";
        using (StreamWriter writer = new StreamWriter(path))
        {
            writer.WriteLine(sb.ToString());
        }
    }

    /// <summary>
    /// 将一行excel转为一行json
    /// </summary>
    /// <param name="fieldType">字段类型列表</param>
    /// <param name="fieldName">字段名列表</param>
    /// <param name="dataList">实际一行数据</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    private static string GetALine(List<string> fieldType, List<string> fieldName, List<string> dataList)
    {
        StringBuilder sb = new StringBuilder();
        //写括号
        sb.Append("{");
        //遍历列表 
        for (int i = 0; i < fieldType.Count; i++)
        {

            //写入主键
            string key = fieldName[i];
            sb.Append($"\"{key}\":");
            //写入值 
            string type = fieldType[i];
            string value = dataList[i];
            if (value is null)
            {
                throw new Exception("表格实际数据存在未配置项");
            }
            sb.Append($"{Convert(type, value)}");
            //写入逗号
            //不是最后一个就是逗号
            if (i != fieldType.Count - 1)
            {
                sb.Append(",");
            }
        }

        sb.Append("}");
        return sb.ToString();
    }

    //根据类型获取键所对应的值
    //如果不是数组 返回类型为 "Key":"Value" 中的value
    //如果是数组 返回类似于 ["1","2"] 的结构
    private static string Convert(string type, string value)
    {
        switch (type)
        {
            case "int":
            case "float":
            case "double":
            case "bool":
            case "string":
            case "long":
                //注此处返回的时候加了引号,避免格式错误
                return $"\"{value}\"";
            case "int[]":
            case "float[]":
            case "double[]":
            case "bool[]":
            case "string[]":
            case "long[]":

                return ArrayParse(value);
            default:
                throw new Exception("{type}类型暂未支持");
        }
    }

    /// <summary>
    /// 将数组转换成对应的字符串
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    private static string ArrayParse(string value)
    {
        //切分字符串得到数组
        var res = value.Split("|");
        StringBuilder sb = new StringBuilder();
        sb.Append("[");
        for (int i = 0; i < res.Length; i++)
        {
            sb.Append('"');
            sb.Append(res[i]);
            sb.Append('"');
            //不是数组最后一个加,
            if (i != res.Length - 1)
            {
                sb.Append(",");
            }
        }

        sb.Append("]");
        return sb.ToString();
    }

}

 

直接获取该项目

ExcelToJson: ExcelToJson

总结

该工具可以帮助你轻松地将 .xlsx 文件中的数据转换为 JSON 文件,并自动生成对应的 C# 脚本,简化了数据处理和代码生成的流程。在使用时,务必遵循 Excel 文件格式要求,确保生成的脚本和 JSON 文件符合预期。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/946024.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深信服云桌面系统的终端安全准入设置

深信服的云桌面系统在默认状态下没有终端的安全准入设置&#xff0c;这也意味着同样的虚拟机&#xff0c;使用云桌面终端或者桌面套件都可以登录&#xff0c;但这也给系统带来了一些安全隐患&#xff0c;所以&#xff0c;一般情况下需要设置终端的安全准入策略&#xff0c;防止…

基于SpringBoot的实验室信息管理系统【源码+文档+部署讲解】

系统介绍 视频演示 基于SpringBootVue实现的实验室信息管理系统采用前后端分离的架构方式&#xff0c;系统分为管理员、老师、用户三种角色&#xff0c;实现了用户管理、设备管理、实验室查询、公告、课程、实验室耗材管理、我的等功能 技术选型 开发工具&#xff1a;idea2…

Windows 10 自带功能实现大屏、小屏无线扩展

一、添加可选功能 在作为无线投屏对象的「第二屏」设备上&#xff0c;打开 Windows 10 设置并定位至「应用 > 应用和功能」界面&#xff0c;然后点击右侧界面中的「可选功能」选项。 点击可选功能界面顶部的「添加功能」按钮&#xff0c;搜索「无线显示器」模块并选择添加。…

大电流和大电压采样电路

大电压采样电路&#xff1a; 需要串联多个电阻进行分压&#xff0c;从而一级一级降低电压&#xff0c;防止电阻损坏或者短路直接打穿MCU。 为什么需要加电压跟随器&#xff1a;进行阻抗的隔离&#xff0c;防止MCU的IO阻抗对分压产生影响&#xff1a; 大电流检测电路&#xff…

torch.nn.functional的用法

文章目录 介绍激活函数示例 损失函数示例 卷积操作示例 池化示例 归一化操作示例 Dropout示例 torch.nn.functional 与 torch.nn 的区别 介绍 torch.nn.functional 是 PyTorch 中的一个模块&#xff0c;提供了许多函数式的神经网络操作&#xff0c;包括激活函数、损失函数、卷…

生物信息学软件开发综述学习

目录 ①编程语言和开源工具和库 ②轻量级 R 包开发 ③大规模组学软件开发 ④示例 1.轻量级 R 包开发示例及数据 2.大规模组学软件开发 文献&#xff1a;Bioinformatics software development: Principles and future directions ①编程语言和开源工具和库 在生物信息学…

【复刻】数字化转型是否赋能企业新质生产力发展?(2015-2023年)

参照赵国庆&#xff08;2024&#xff09;的做法&#xff0c;对来自产业经济评论《企业数字化转型是否赋能企业新质生产力发展——基于中国上市企业的微观证据》一文中的基准回归部分进行复刻基于2015-2023年中国A股上市公司数据&#xff0c;实证分析企业数字化转型对新质生产力…

在线免费批量生成 Word 文档工具

为了方便的批量生成 Word 文档&#xff0c;写了个在线 Word 文档批量生成工具&#xff0c;可以根据 Excel 数据和 Word 模板批量生成大量个性化的 Word 文档。适用于需要批量生成格式统一但内容不同的文档场景。比如&#xff1a; 批量生成证书、奖状批量生成合同、协议批量生成…

3D数学基础2

矩阵的行列式 在任意方阵中都存在至少一个标量&#xff0c;称作该方阵的行列式。在线性代数中&#xff0c;行列式有很多有用的性质 线性运算法则 方阵 M M M的行列式记作 ∣ M ∣ |M| ∣M∣或“det M”。非方阵矩阵的行列式是未定义的。 注意&#xff0c;在书写行列式时&…

2024国产化信创产品名录

文章目录 一、JDK/OpenJDK替代品1、龙芯JDK2、阿里巴巴Dragonwell3、毕昇JDK4、腾讯 Kona 二、Tomcat替代品1、东方通TongWeb2、宝兰德Web服务器软件3、普元信息Primeton AppServer4、金蝶天燕AAS应用服务器 三、Nginx替代品1、宝兰德WebServer2、东方通TongHttpServer3、Tengi…

OpenCV-Python实战(11)——边缘检测

一、Sobel 算子 通过 X 梯度核与 Y 梯度核求得图像在&#xff0c;水平与垂直方向的梯度。 img cv2.Sobel(src*,ddepth*,dx*,dy*,ksize*,scale*,delta*,borderType*)img&#xff1a;目标图像。 src&#xff1a;原始图像。 ddepth&#xff1a;目标图像深度&#xff0c;-1 代表…

基于微博热搜评论的情感分析与热点主题挖掘研究

目录 1、绪论 1.1 研究背景与研究意义 1.2 数据来源 1.3 技术路线 2、数据预处理 2.1 数据清洗与准备 2.2 导入必要库与加载数据 2.3 加载停用词表与分词处理 2.4 统计词频与高频词分析 3、情感分析与主题建模 3.1 情感分析 3.2 主题建模 3.3 热点主题识别 4、数据可视…

【毕业设计选题】目标检测方向毕业设计选题推荐 2025

目录 前言 毕设选题 开题指导建议 更多精选选题 选题帮助 最后 前言 大家好,这里是海浪学长毕设专题! 大四是整个大学期间最忙碌的时光&#xff0c;一边要忙着准备考研、考公、考教资或者实习为毕业后面临的升学就业做准备,一边要为毕业设计耗费大量精力。学长给大家整…

Windows onnxruntime编译openvino

理论上来说&#xff0c;可以直接访问 ONNXRuntime Releases 下载 dll 文件&#xff0c;然后从官方文档中下载缺少的头文件以直接调用&#xff0c;但我没有尝试过。 1. 下载 OpenVINO 包 从官网下载 OpenVINO 的安装包并放置在 C:\Program Files (x86) 路径下&#xff0c;例如…

PCB设计检查助手——焊盘中间丝印检查

焊盘中间丝印检查功能用于检查双引脚元件中间是否有垂直两个焊盘连线的元件&#xff0c;由于较大双贴片引脚不用考虑中间的丝印&#xff0c;在检查时会自动过滤两个引脚大于1mm以上的元件&#xff0c;此功能在检查时&#xff0c;两个引脚的间距小于等于1mm&#xff0c;且元件的…

LiteFlow 流程引擎引入Spring boot项目集成pg数据库

文章目录 官网地址简要项目引入maven 所需jar包配置 PostgreSQL 数据库表使用LiteFlow配置 yml 文件通过 代码方式使用 liteflow数据库sql 数据在流程中周转 官网地址 https://liteflow.cc/ 简要 如果你要对复杂业务逻辑进行新写或者重构&#xff0c;用LiteFlow最合适不过。…

MATLAB学习-1 蚁群算法解决TSP问题

matlab安装可以在网上找一个安装教程,我安装的是R2020a版本的。 学习解决该问题 利用蚁群算法对给定的TSP问题进行求解,求出一条最短路径。 用的是194个城市的TSPLIB数据集,如果需要TSPLIB数据集可点击 tsp、添加了可视化,迭代400次,目前最短路径为10576.5454,实现效果如…

IP寻址映射与网络通信互联

IP寻址映射 IP寻址映射能够让数据准确传输的重要部分。在网络之中&#xff0c;所有联网的设备都具有一个IP地址&#xff0c;而IP寻址映射就是负责将IP地址与设备位置或其他相关标识相联系起来&#xff0c;确保数据找到正确的路径传输&#xff0c;保障网络能够畅通。 动态主机配…

IO Virtualization with Virtio.part 1 [十二]

久等了各位&#xff01; 本篇开始讲解 IO 虚拟化中的 virtio&#xff0c;我会以 Linux 的 IIC 驱动为例&#xff0c;从 IIC 驱动的非虚拟化实现&#xff0c;到 IIC 驱动的半虚拟化实现&#xff0c;再到最后 X-Hyper 中如何通过 virtio 来实现前后端联系&#xff0c;一步步把 v…

ITOM系统在IT运维中的作用

在企业IT运维中&#xff0c;ITOM系统&#xff08;IT运营管理&#xff09;通过整合、自动化和监控&#xff0c;能够帮助企业有效管理IT基础设施&#xff0c;提高运维效率和系统的可靠性。本文将从多个角度探讨ITOM系统在IT运维中的作用及其功能。 提升运维效率&#xff1a;统一平…