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;//脚本目录private static readonly string scriptsFolder = excel + "/ExcelScripts";//json目录private static string jsonFolder = excel + "/Json";[MenuItem("ExcelTool/读取Excel")]public static void TestTool(){// 设置为非商业许可(适用于开源版本)ExcelPackage.LicenseContext = LicenseContext.NonCommercial;// 获取目录下所有以 .xlsx 结尾的文件(不包括子目录中的文件)string[] files = Directory.GetFiles(excel, "*.xlsx");if (files.Length > 0){// 获取第一个文件的完整路径string firstFilePath = files[0];// 获取文件名(不包括路径)string fileName = Path.GetFileName(firstFilePath);excelFilePath = excel + "/" + 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;}#endregionusing (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

如果遭遇空白行问题

选择第一个空白行比如是A3,然后如下图

总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

牛客网刷题 ——C语言初阶(6指针)——字符逆序

1. 题目描述&#xff1a;字符逆序 牛客网题目链接 将一个字符串str的内容颠倒过来&#xff0c;并输出。 输入描述: 输入一个字符串&#xff0c;可以有空格 输出描述: 输出逆序的字符串 示例1 输入 I am a student 输出 tneduts a ma I 2. 思路 首先字符串逆序&#xff0c;之…

【USRP】教程:在Macos M1(Apple芯片)上安装UHD驱动(最正确的安装方法)

Apple芯片 前言安装Homebrew安装uhd安装gnuradio使用b200mini安装好的路径下载固件后续启动频谱仪功能启动 gnu radio关于博主 前言 请参考本文进行安装&#xff0c;好多人买了Apple芯片的电脑&#xff0c;这种情况下&#xff0c;可以使用UHD吗&#xff1f;答案是肯定的&#…

141.《mac m系列芯片安装mongodb详细教程》

文章目录 下载从官网下载安装包 下载后双击解压出文件夹安装文件名修改为 mongodb配置data存放位置和日志log的存放位置启动方式一方式二方式二:输入mongo报错以及解决办法 本人电脑 m2 pro,属于 arm 架构 下载 官网地址: mongodb官网 怎么查看自己电脑应该下载哪个版本,输入…

Elasticsearch:基础概念

这里写目录标题 一、什么是Elasticsearch1、基础介绍2、什么是全文检索3、倒排索引4、索引&#xff08;1&#xff09;创建索引a 创建索引基本语法b 只定义索引名&#xff0c;setting、mapping取默认值c 创建一个名为student_index的索引&#xff0c;并设置一些自定义字段 &…

Dexcap复现代码数据预处理全流程(四)——demo_clipping_3d.py

此脚本的主要功能是可视化点云数据文件&#xff08;.pcd 文件&#xff09;&#xff0c;并通过键盘交互选择演示数据的起始帧和结束帧&#xff0c;生成片段标记文件 (clip_marks.json) 主要流程包括&#xff1a; 用户指定数据目录&#xff1a;检查目录是否存在并处理标记文件 -…

安装Cockpit服务,使用Web页面管理你的Linux服务器

说起管理 Linux 服务器&#xff0c;大家首先想到的使用 SecureCRT、Xshell、MobaXterm 等工具远程到服务器&#xff0c;然后使用命令行管理服务器。今天给大家介绍一个好玩的工具&#xff0c;名字叫Cockpit&#xff0c; Cockpit 是一个免费开源的基于 web 的 Linux 服务器管理…

[A-25]ARMv8/v9-GIC的系统架构(中断的硬件基础)

ver0.1 前言 我们在观看很多的影视剧过程中,尤其是军旅体裁类型的布景中,经常会看见高级干部的办公桌上都会有几部电话机。这样的电话可不能小看,重要的事情尤其是突发和紧急的情况都要通过这几部电话第一时间通知给决策者。这几部电话,必须举报几个特点:及时性好、稳定…

13-线段的转折点样式

13-线段的转折点样式_哔哩哔哩_bilibili13-线段的转折点样式是一次性学会 Canvas 动画绘图&#xff08;核心精讲50个案例&#xff09;2023最新教程的第14集视频&#xff0c;该合集共计53集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https://www.bi…

计算机网络 (28)虚拟专用网VPN

前言 虚拟专用网络&#xff08;VPN&#xff09;是一种在公共网络上建立私有网络连接的技术&#xff0c;它允许远程用户通过加密通道访问内部网络资源&#xff0c;实现远程办公和安全通信。 一、基本概念 定义&#xff1a;VPN是一种通过公共网络&#xff08;如互联网&#xff09…

基于transformer的目标检测:DETR

目录 一、背景介绍 二、DETR的工作流程 三、DETR的架构 1. 损失函数 2. 网络框架讲解及举例 一、背景介绍 在深度学习和计算机视觉领域&#xff0c;目标检测一直是一个核心问题。传统方法依赖于复杂的流程和手工设计的组件&#xff0c;如非极大值抑制&#xff08;nms&…

Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)

Vue Amazing UI 一个 Vue 3 组件库 使用 TypeScript&#xff0c;都是单文件组件 (SFC)&#xff0c;支持 tree shaking 有点意思 English | 中文 Vue Amazing UI 是一个基于 Vue 3、TypeScript、Vite 等最新技术栈开发构建的现代化组件库&#xff0c;包含丰富的 UI 组件和常…

C语言----指针

目录 1.概念 2.格式 3.指针操作符 4.初始化 1. 将普通变量的地址赋值给指针变量 a. 将数组的首地址赋值给指针变量 b. 将指针变量里面保存的地址赋值给另一个指针变量 5.指针运算 5.1算术运算 5.2 关系运算 指针的大小 总结&#xff1a; 段错误 指针修饰 1. con…

Python应用——将Matplotlib图形嵌入Tkinter窗口

Python应用——将Matplotlib图形嵌入Tkinter窗口 目录 Python应用——将Matplotlib图形嵌入Tkinter窗口1 模块简介2 示例代码2.1 Matplotlib嵌入Tkinter2.2 Matplotlib嵌入Tkinter并显示工具栏 1 模块简介 Tkinter是Python的标准GUI&#xff08;图形用户界面&#xff09;库&…

【linux基础I/O(2)】理解文件系统|文件缓冲区|软硬链接|动静态库

目录 前言1. 理解C语言的缓冲区2. 对文件系统的初认识3. 理解软硬链接1. 软硬链接的特征2.软硬链接的作用 4. 理解动静态库5. 总结 前言 对于文件来讲,有打开的在内存中的文件,也有没有打开的在磁盘上文件,上一篇文章讲解的是前者,本篇文章将带大家了解后者! 本章重点: 本篇文…

什么是Redis的渐进式ReHash?

文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ Redis 的渐进式 rehash 是一…

Linux应用软件编程--网络通信(udp协议,tcp协议)

网络通信&#xff1a;不同主机&#xff0c;进程间通信&#xff0c;分为广域网和局域网 OSI 七层模型&#xff1a;是一种理论模型 应用层&#xff1a;通信传输的数据内容 http、FTP、TFTP、MQTT 表述层&#xff1a;数据加密&#xff0c;解密操作&#xff0c;压缩&#xff…

【C++】构造函数与析构函数

写在前面 构造函数与析构函数都是属于类的默认成员函数&#xff01; 默认成员函数是程序猿不显示声明定义&#xff0c;编译器会中生成。 构造函数和析构函数的知识需要建立在有初步类与对象的基础之上的&#xff0c;关于类与对象不才在前面笔记中有详细的介绍&#xff1a;点我…

【简博士统计学习方法】3. 统计学习方法的三要素

3. 统计学习方法的三要素 3.1 监督学习的三要素 3.1.1 模型 假设空间&#xff08;Hypothesis Space&#xff09;&#xff1a;所有可能的条件概率分布或决策函数&#xff0c;用 F \mathcal{F} F表示。 若定义为决策函数的集合&#xff1a; F { f ∣ Y f ( X ) } \mathcal{F…

【llm/ollama/qwen】在本地部署qwen2.5-coder并在vscode中集成使用代码提示功能

说在前面 操作系统&#xff1a;windows11ollama版本&#xff1a;0.5.4vscode版本&#xff1a;1.96.2continue插件版本&#xff1a;0.8.66 ollama安装 访问官网&#xff0c;点击下载安装即可 默认装在了C盘&#xff0c;比较蛋疼&#xff1b;但是可以指定路径安装&#xff1a;Ol…

PHP零基础入门笔记

表达式&#xff1a;任何有值的东西就是表达式 php可以解析双引号&#xff0c;不可以解析单引号&#xff0c;双引号中引用变量可以输出引用变量的值&#xff0c;但是单引号不可以 1.变量和变量的销毁 unset(变量名) //销毁变量 变量是严格区分大小写的&#xff0c;在php中…