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

格式

保证这个目录格式

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;}#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

总结

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

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

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

相关文章

Python:爬虫基础《爬取红楼梦》

小说爬虫项目说明文档 用于爬取诗词名句网上小说内容的Python爬虫项目。本项目以《红楼梦》为例&#xff0c;演示如何爬取完整的小说内容。 项目功能 爬取小说的所有章节名称获取每个章节的URL链接下载并保存每个章节的内容到独立的文本文件自动创建存储目录包含基本的错误处…

HTTPS验证流程

http通常是直接和TCP进行通信的&#xff0c;而https中http是和SSL通信&#xff0c;再由SSL与TCP进行通信。SSL协议是一个介于应用层和传输层之间的一个安全协议。 1.对称加密与非对称加密 对称加密&#xff1a; 加密和解密方式都使用同一个私钥和公开的加密算法&#xff0c;优…

履约系统:应用层、领域层、集成关系设计

在这篇文章中&#xff0c;我们一起探讨订单履约系统的应用架构设计。 应用架构设计 我们前面讨论了系统的核心概念模型和拆单逻辑。接下来&#xff0c;让我们从应用架构的角度&#xff0c;深入了解系统的各个层次。这包括应用层、领域层&#xff0c;以及与其他系统的集成关系。…

python利用selenium实现大麦网抢票

大麦网&#xff08;damai.cn&#xff09;是中国领先的现场娱乐票务平台&#xff0c;涵盖演唱会、音乐会、话剧、歌剧、体育赛事等多种门票销售。由于其平台上经常会有热门演出&#xff0c;抢票成为许多用户关注的焦点。然而&#xff0c;由于票务资源的有限性&#xff0c;以及大…

神经网络-SENet

SENet是一种用于图像分类的卷积神经网络模型&#xff0c;由Jie Hu等人在2018年提出。SENet的全称是“Squeeze-and-Excitation Network”&#xff0c;其核心思想是通过自适应地调整每个通道的特征图权重&#xff0c;来增强卷积神经网络对于不同特征的感知能力。 SENet的设计灵感…

【spring】参数校验Validation

前言 在实际开发中&#xff0c;我们无法保证客户端传来的请求都是合法的。比如一些要求必传的参数没有传递&#xff0c;传来的参数长度不符合要求等&#xff0c;这种时候如果放任不管&#xff0c;继续执行后续业务逻辑&#xff0c;很有可能就会出现意想不到的bug。 有人可能会…

sentinel-请求限流、线程隔离、本地回调、熔断

请求限流&#xff1a;控制QPS来达到限流的目的 线程隔离&#xff1a;控制线程数量来达到限流的目录 本地回调&#xff1a;当线程被限流、隔离、熔断之后、就不会发起远程调用、而是使用本地已经准备好的回调去提醒用户 服务熔断&#xff1a;熔断也叫断路器&#xff0c;当失败、…

github提交不上去,网络超时问题解决

问题出现的原因&#xff1a; DNS服务器数据不同步&#xff0c;github的服务器发送迁移&#xff0c;在本地缓存的ip地址现在无效了。 解决方案&#xff1a; 1&#xff09;点击这里&#xff0c;查询github.com最新的ip地址 2.0&#xff09;编辑linux系统地址缓存文件&#x…

哪些框架、软件、中间件使用了netty? 哪些中间件、软件底层使用了epoll?

使用 Netty 的软件、中间件和框架 Netty 是一个异步事件驱动的网络应用框架&#xff0c;广泛应用于构建高性能的网络应用程序。以下是一些使用了 Netty 的知名软件、中间件和框架&#xff1a; 1. Elasticsearch 描述&#xff1a;Elasticsearch 是一个分布式的搜索和分析引擎…

C++和OpenGL实现3D游戏编程【连载19】——着色器光照初步(平行光和光照贴图)(附源码)

1、本节要实现的内容 我们在前期的教程中,讨论了在即时渲染模式下的光照内容。但在我们后期使用着色器的核心模式下,会经常在着色器中使光照,我们这里就讨论一下着色器光照效果,以及光照贴图效果,同时这里知识会为后期的更多光照效果做一些铺垫。本节我们首先讨论冯氏光照…

如何恢复永久删除的PPT文件?查看数据恢复教程!

可以恢复永久删除的PPT文件吗&#xff1f; Microsoft PowerPoint应用程序是一种应用广泛的演示程序&#xff0c;在人们的日常生活中经常使用。商人、官员、学生等在学习和工作中会使用PowerPoint做报告和演示。PowerPoint在人们的学习和工作生活中占主导地位&#xff0c;每天都…

基于Spark的共享单车数据存储系统的设计与实现_springboot+vue

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

本地运行stable-diffusion3.5

本地运行stable-diffusion3.5 本地运行stable-diffusion3.5准备工作下载ComfyUI 和需要的模型文件需要下载以下几类SD3.5 文件 启动ComfyUI启动在工作流中分别选中三个Clip 模型 sd3.5_large_turbo准备 本地运行stable-diffusion3.5 AI 时代不可阻挡&#xff0c;给老机器加了个…

mysql高频面试题

1. mysql里的索引类型 2. 聚簇索引和非聚簇索引的区别 聚簇索引适合场景: 主键、唯一性要求高的字段。需要对数据进行范围查询时。对数据的读取频繁,并且数据行的插入和删除较少时。非聚簇索引适合场景: 较多的查询条件,或者需要基于某些非主键字段进行查询时。需要创建多个…

每日一练 | 时延和抖动

01 真题题目 关于时延和抖动&#xff0c;下面描述正确的是&#xff08;多选&#xff09;&#xff1a; A. 端到端时延等于处理时延与队列时延之和 B. 抖动是因为每个包的端到端时延不相等造成的 C. 抖动的大小跟时延的大小相关&#xff0c;时延小则抖动的范围也小&#xff0c;时…

MySQL第二弹----CRUD

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;MySQL &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ 一、修改表 使用ALTER …

c++解决常见内存泄漏问题——智能指针的使用及其原理

目录 前言&#xff1a; 1. 智能指针的使用及其原理 1. 1 智能指针的使用场景分析 1.2 RAII和智能指针的设计思路 1.3 C标准库智能指针的使用 1.3 1 auto_ptr 1.3 2 unique_ptr 1.3 3 shared_ptr(重&#xff09; 1.3 4 weak_ptr 1.3 5 模拟实现删除器 2.智能指针的原…

NVR管理平台EasyNVR设备通过ONVIF接入出现404访问错误是什么原因?

如今&#xff0c;视频监控在各行各业都得到了广泛应用&#xff0c;成为现代社会不可或缺的一部分。随着技术的不断进步&#xff0c;视频监控系统已经从传统的模拟监控发展到高清化、网络化和智能化阶段&#xff0c;其应用领域也从最初的安防扩展到智慧城市、智能家居、交通管理…

【python中级】 控制文件大小的简易日志

【python中级】 控制文件大小的简易日志 1.背景2.简单版本3.复杂实现1.背景 日志(Log)在软件开发和运行中扮演了重要的角色,主要用于记录系统运行过程中的事件和状态信息。日志的核心作用是记录、分析和追踪,不仅对开发者和运维人员有用,还能为用户体验、安全性和业务决策…

Apollo中间件技术:从入门到精通

一、引言 在Java开发的微服务架构中&#xff0c;配置管理是一个不可或缺的重要环节。随着服务数量的增加和部署环境的复杂化&#xff0c;传统的手动配置管理方式已难以满足需求。Apollo作为一款开源的分布式配置中心&#xff0c;凭借其强大的功能和灵活的架构&#xff0c;成为…