当前位置:网站首页>[unity] upgraded version · Excel data analysis, automatically create corresponding C classes, automatically create scriptableobject generation classes, and automatically serialize asset files
[unity] upgraded version · Excel data analysis, automatically create corresponding C classes, automatically create scriptableobject generation classes, and automatically serialize asset files
2022-07-06 22:50:00 【InfoQ】
Realization function :
- Automatically create inheritance ScriptableObject Of C# Data class , Every one of them Excel The data of , Have corresponding fields Get function ;
- Automatically create each Excel Of Asset Generate classes and generate functions , Used to automatically generate Asset file
- use Asset Automatic serialization of generated classes Excel Data to Asset file , It can be loaded and used directly when the project is running
Realization principle :
Excel Configuration format :
- The first 1 Lines correspond to special marks ( Validity can be set , Specify the file to create )
- The first 2 The line corresponds to the Chinese description ( As a first 3 Comments for line fields )
- The first 3 Row corresponding field name ( Automatically created field name )
- The first 4 The row corresponds to the field type ( Automatically created field types , One to one correspondence with field name )
- The first 5 Row and subsequent corresponding field values ( All the data , Analyze in behavioral units 、 Save the data )
- The fixed fields in the first column are "id", Is the index of each line of data in the code Key
- Field name line , Add "//", You can annotate this field , Will not parse to C# class ;
- Add "//", You can annotate a line of data , It won't be saved to Asset In file ;
- Comments can be used to add a description line , Or eliminate the specified useless data .
Generated C# Class format :
[Serializable]
public class TestConfigExcelItem : ExcelItemBase
{
/// <summary>
/// data id
/// </summary>>
public int id;
/// <summary>
/// character string
/// </summary>>
public string testString;
/// <summary>
/// Int
/// </summary>>
public int testInt;
/// <summary>
/// Float
/// </summary>>
public float testFloat;
}
public class TestConfigExcelData : ExcelDataBase<TestConfigExcelItem>
{
public TestConfigExcelItem[] items;
public Dictionary<int,TestConfigExcelItem> itemDic = new Dictionary<int,TestConfigExcelItem>();
public void Init()
{
itemDic.Clear();
if(items != null && items.Length > 0)
{
for(int i = 0; i < items.Length; i++)
{
itemDic.Add(items[i].id, items[i]);
}
}
}
public TestConfigExcelItem GetTestConfigExcelItem(int id)
{
if(itemDic.ContainsKey(id))
return itemDic[id];
else
return null;
}
#region --- Get Method ---
public string GetTestString(int id)
{
var item = GetTestConfigExcelItem(id);
if(item == null)
return default;
return item.testString;
}
// ··· ···
#endregion
}
Currently supported data structures :
[Serializable]
public struct StringArr
{
public string[] array;
}
// Two dimensional array representation : StringArr[]
Asset Data files :
advantage :
- After data modification, you only need to regenerate with one click
- Every Excel Corresponding to a class , Flexible use , Yes Excel Less restrictions
- Automatically create C# class , There is no need for each Excel Write code manually , Each data corresponds to a field , There is no need to unpack and decorate
- Automatically create ScriptableObject Of Asset file , Automatically serialize data , Convenient view , You can manually modify and adjust , There is no need to change every time Excel In the operation
- Read directly in the game Asset Of ScriptableObject Subclass , No need for extra operation , The business layer directly accesses data fields
Usage method :
- Configure in standard format Excel
- One click generation C# class 、Asset file
- The project runtime loads Asset resources , call Init initialization ,Get Function to get the corresponding field value
Complete code :
Expand Unity Editor window :
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using System.Linq;
public class BuildExcelWindow : EditorWindow
{
[MenuItem("MyTools/Excel Window",priority = 100)]
public static void ShowReadExcelWindow()
{
BuildExcelWindow window = GetWindow<BuildExcelWindow>(true);
window.Show();
window.minSize = new Vector2(475,475);
}
//Excel Read path , Absolute path , Put it in Assets Peer path
private static string excelReadAbsolutePath;
// Automatic generation C# Class file path , Absolute path
private static string scriptSaveAbsolutePath;
private static string scriptSaveRelativePath;
// Automatic generation Asset File path , Relative paths
private static string assetSaveRelativePath;
private List<string> fileNameList = new List<string>();
private List<string> filePathList = new List<string>();
private void Awake()
{
titleContent.text = "Excel Configuration table read ";
excelReadAbsolutePath = Application.dataPath.Replace("Assets","Excel");
scriptSaveAbsolutePath = Application.dataPath + CheckEditorPath("/Script/Excel/AutoCreateCSCode");
scriptSaveRelativePath = CheckEditorPath("Assets/Script/Excel/AutoCreateCSCode");
assetSaveRelativePath = CheckEditorPath("Assets/AssetData/Excel/AutoCreateAsset");
}
private void OnEnable()
{
RefreshExcelFile();
}
private void OnDisable()
{
fileNameList.Clear();
filePathList.Clear();
}
private Vector2 scrollPosition = Vector2.zero;
private void OnGUI()
{
GUILayout.Space(10);
scrollPosition = GUILayout.BeginScrollView(scrollPosition,GUILayout.Width(position.width),GUILayout.Height(position.height));
// Show the way
GUILayout.BeginHorizontal(GUILayout.Height(20));
if(GUILayout.Button("Excel Read path ",GUILayout.Width(100)))
{
EditorUtility.OpenWithDefaultApp(excelReadAbsolutePath);
Debug.Log(excelReadAbsolutePath);
}
if(GUILayout.Button("Script Save the path ",GUILayout.Width(100)))
{
SelectObject(scriptSaveRelativePath);
}
if(GUILayout.Button("Asset Save the path ",GUILayout.Width(100)))
{
SelectObject(assetSaveRelativePath);
}
GUILayout.EndHorizontal();
GUILayout.Space(5);
//Excel list
GUILayout.Label("Excel list :");
for(int i = 0; i < fileNameList.Count; i++)
{
GUILayout.BeginHorizontal("Box",GUILayout.Height(40));
GUILayout.Label($"{i}:","Titlebar Foldout",GUILayout.Width(30),GUILayout.Height(35));
GUILayout.Box(fileNameList[i],"MeTransitionBlock",GUILayout.MinWidth(200),GUILayout.Height(35));
GUILayout.Space(10);
// Generate CS Code
if(GUILayout.Button("Create Script",GUILayout.Width(100),GUILayout.Height(30)))
{
ExcelDataReader.ReadOneExcelToCode(filePathList[i],scriptSaveAbsolutePath);
}
// Generate Asset file
if(GUILayout.Button("Create Asset",GUILayout.Width(100),GUILayout.Height(30)))
{
ExcelDataReader.CreateOneExcelAsset(filePathList[i],assetSaveRelativePath);
}
GUILayout.EndHorizontal();
GUILayout.Space(5);
}
GUILayout.Space(10);
// One click processing all Excel
GUILayout.Label(" One click operation :");
GUILayout.BeginHorizontal("Box",GUILayout.Height(40));
GUILayout.Label("all","Titlebar Foldout",GUILayout.Width(30),GUILayout.Height(35));
GUILayout.Box("All Excel","MeTransitionBlock",GUILayout.MinWidth(200),GUILayout.Height(35));
GUILayout.Space(10);
if(GUILayout.Button("Create Script",GUILayout.Width(100),GUILayout.Height(30)))
{
ExcelDataReader.ReadAllExcelToCode(excelReadAbsolutePath,scriptSaveAbsolutePath);
}
if(GUILayout.Button("Create Asset",GUILayout.Width(100),GUILayout.Height(30)))
{
ExcelDataReader.CreateAllExcelAsset(excelReadAbsolutePath,assetSaveRelativePath);
}
GUILayout.EndHorizontal();
//
GUILayout.Space(20);
//
GUILayout.EndScrollView();
}
// Read the... Under the specified path Excel file name
private void RefreshExcelFile()
{
fileNameList.Clear();
filePathList.Clear();
if(!Directory.Exists(excelReadAbsolutePath))
{
Debug.LogError(" Invalid path :" + excelReadAbsolutePath);
return;
}
string[] excelFileFullPaths = Directory.GetFiles(excelReadAbsolutePath,"*.xlsx");
if(excelFileFullPaths == null || excelFileFullPaths.Length == 0)
{
Debug.LogError(excelReadAbsolutePath + " Not found under path Excel file ");
return;
}
filePathList.AddRange(excelFileFullPaths);
for(int i = 0; i < filePathList.Count; i++)
{
fileNameList.Add(Path.GetFileName(filePathList[i]));
}
Debug.Log(" find Excel file :" + fileNameList.Count + " individual ");
}
private void SelectObject(string targetPath)
{
Object targetObj = AssetDatabase.LoadAssetAtPath<Object>(targetPath);
EditorGUIUtility.PingObject(targetObj);
Selection.activeObject = targetObj;
Debug.Log(targetPath);
}
private static string CheckEditorPath(string path)
{
#if UNITY_EDITOR_WIN
return path.Replace("/","\\");
#elif UNITY_EDITOR_OSX
return path.Replace("\\","/");
#else
return path;
#endif
}
}
Excel Data reading class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using Excel;
using System.Reflection;
using System;
using System.Linq;
public class ExcelDataReader
{
//Excel The first 1 Lines correspond to special marks
private const int specialSignRow = 0;
//Excel The first 2 The line corresponds to the Chinese description
private const int excelNodeRow = 1;
//Excel The first 3 Row corresponding field name
private const int excelNameRow = 2;
//Excel The first 4 The row corresponds to the field type
private const int excelTypeRow = 3;
//Excel The first 5 Row and subsequent corresponding field values
private const int excelDataRow = 4;
// Mark comment lines / Column
private const string annotationSign = "//";
#region --- Read Excel ---
// establish Excel Corresponding C# class
public static void ReadAllExcelToCode(string allExcelPath,string codeSavePath)
{
// Read all Excel file
// The full name of the file in the specified directory that matches the specified search pattern and options ( Inclusion path ) Array of ; If no files are found , Is an empty array .
string[] excelFileFullPaths = Directory.GetFiles(allExcelPath,"*.xlsx");
if(excelFileFullPaths == null || excelFileFullPaths.Length == 0)
{
Debug.Log("Excel file count == 0");
return;
}
// Traverse all of Excel, establish C# class
for(int i = 0; i < excelFileFullPaths.Length; i++)
{
ReadOneExcelToCode(excelFileFullPaths[i],codeSavePath);
}
}
// establish Excel Corresponding C# class
public static void ReadOneExcelToCode(string excelFullPath,string codeSavePath)
{
// analysis Excel Get intermediate data
ExcelMediumData excelMediumData = CreateClassCodeByExcelPath(excelFullPath);
if(excelMediumData == null)
{
Debug.LogError($" Read Excel Failure : {excelFullPath}");
return;
}
if(!excelMediumData.isValid)
{
Debug.LogError($" Read Excel Failure ,Excel Mark failure : {excelMediumData.excelName}");
return;
}
if(!excelMediumData.isCreateCSharp && !excelMediumData.isCreateAssignment)
{
Debug.LogError($" Read Excel Failure ,Excel Generation of CSCode : {excelMediumData.excelName}");
return;
}
// Generate... From data C# Script
string classCodeStr = ExcelCodeCreater.CreateCodeStrByExcelData(excelMediumData);
if(string.IsNullOrEmpty(classCodeStr))
{
Debug.LogError($" analysis Excel Failure : {excelMediumData.excelName}");
return;
}
// Check the export path
if(!Directory.Exists(codeSavePath))
Directory.CreateDirectory(codeSavePath);
// Class name
string codeFileName = excelMediumData.excelName + "ExcelData";
// Writing documents , Generate CS Class file
StreamWriter sw = new StreamWriter($"{codeSavePath}/{codeFileName}.cs");
sw.WriteLine(classCodeStr);
sw.Close();
//
UnityEditor.AssetDatabase.SaveAssets();
UnityEditor.AssetDatabase.Refresh();
//
Debug.Log($" Generate Excel Of CS success : {excelMediumData.excelName}");
}
#endregion
#region --- Create Asset ---
// establish Excel Corresponding Asset Data files
public static void CreateAllExcelAsset(string allExcelPath,string assetSavePath)
{
// Read all Excel file
// The full name of the file in the specified directory that matches the specified search pattern and options ( Inclusion path ) Array of ; If no files are found , Is an empty array .
string[] excelFileFullPaths = Directory.GetFiles(allExcelPath,"*.xlsx");
if(excelFileFullPaths == null || excelFileFullPaths.Length == 0)
{
Debug.Log("Excel file count == 0");
return;
}
// Traverse all of Excel, establish Asset
for(int i = 0; i < excelFileFullPaths.Length; i++)
{
CreateOneExcelAsset(excelFileFullPaths[i],assetSavePath);
}
}
// establish Excel Corresponding Asset Data files
public static void CreateOneExcelAsset(string excelFullPath,string assetSavePath)
{
// analysis Excel Get intermediate data
ExcelMediumData excelMediumData = CreateClassCodeByExcelPath(excelFullPath);
if(excelMediumData == null)
{
Debug.LogError($" Read Excel Failure : {excelFullPath}");
return;
}
if(!excelMediumData.isValid)
{
Debug.LogError($" Read Excel Failure ,Excel Mark failure : {excelMediumData.excelName}");
return;
}
if(!excelMediumData.isCreateAsset)
{
Debug.LogError($" Read Excel Failure ,Excel Generation of Asset : {excelMediumData.excelName}");
return;
}
//// Get the current assembly
//Assembly assembly = Assembly.GetExecutingAssembly();
//// Create an instance of a class , Return to object type , A cast is required ,assembly.CreateInstance(" The fully qualified name of the class ( Including the namespace )");
//object class0bj = assembly.CreateInstance(excelMediumData.excelName + "Assignment",true);
// You must traverse all assemblies to get the type . The current in Assembly-CSharp-Editor in , The target type is Assembly-CSharp in , Different programs will not be able to get types
Type assignmentType = null;
string assetAssignmentName = excelMediumData.excelName + "AssetAssignment";
foreach(var asm in AppDomain.CurrentDomain.GetAssemblies())
{
// Find the target type
Type tempType = asm.GetType(assetAssignmentName);
if(tempType != null)
{
assignmentType = tempType;
break;
}
}
if(assignmentType == null)
{
Debug.LogError($" Creation boundary Asset Failure , Not found Asset Generating classes : {excelMediumData.excelName}");
return;
}
// Reflection acquisition method
MethodInfo methodInfo = assignmentType.GetMethod("CreateAsset");
if(methodInfo == null)
{
if(assignmentType == null)
{
Debug.LogError($" Creation boundary Asset Failure , Not found Asset Create a function : {excelMediumData.excelName}");
return;
}
}
methodInfo.Invoke(null,new object[] { excelMediumData,assetSavePath });
// establish Asset File successfully
Debug.Log($" Generate Excel Of Asset success : {excelMediumData.excelName}");
}
#endregion
#region --- private ---
// analysis Excel, Create intermediate data
private static ExcelMediumData CreateClassCodeByExcelPath(string excelFileFullPath)
{
if(string.IsNullOrEmpty(excelFileFullPath))
return null;
excelFileFullPath = excelFileFullPath.Replace("\\","/");
// Read Excel
FileStream stream = File.Open(excelFileFullPath,FileMode.Open,FileAccess.Read);
if(stream == null)
return null;
// analysis Excel
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
// Invalid Excel
if(excelReader == null || !excelReader.IsValid)
{
Debug.Log("Invalid excel : " + excelFileFullPath);
return null;
}
Debug.Log(" Start parsing Excel : " + excelReader.Name);
// Record Excel data
ExcelMediumData excelMediumData = new ExcelMediumData();
//Excel name
excelMediumData.excelName = excelReader.Name;
// Currently traversed rows
int curRowIndex = 0;
// Start reading , Go through... By line
while(excelReader.Read())
{
// No data is read in this line , Treat as invalid row data
if(excelReader.FieldCount <= 0)
{
curRowIndex++;
continue;
}
// Read the complete data of each row
string[] datas = new string[excelReader.FieldCount];
for(int j = 0; j < excelReader.FieldCount; ++j)
{
// You can directly read the specified type of data , However, only limited data types are supported , Read uniformly here string, Then data conversion
//excelReader.GetInt32(j); excelReader.GetFloat(j);
// Read every cell data
datas[j] = excelReader.GetString(j);
}
switch(curRowIndex)
{
case specialSignRow:
// Special mark line
string specialSignStr = datas[0];
if(specialSignStr.Length >= 4)
{
excelMediumData.isValid = specialSignStr[0] == 'T';
excelMediumData.isCreateCSharp = specialSignStr[1] == 'T';
excelMediumData.isCreateAssignment = specialSignStr[2] == 'T';
excelMediumData.isCreateAsset = specialSignStr[3] == 'T';
}
else
{
Debug.LogError(" Not resolved to special tag ");
}
break;
case excelNodeRow:
// Data comment line
excelMediumData.propertyNodeArray = datas;
break;
case excelNameRow:
// Data name row
excelMediumData.propertyNameArray = datas;
// Comment column number
for(int i = 0; i < datas.Length; i++)
{
if(string.IsNullOrEmpty(datas[i]) || datas[i].StartsWith(annotationSign))
excelMediumData.annotationColList.Add(i);
}
break;
case excelTypeRow:
// Data type row
excelMediumData.propertyTypeArray = datas;
break;
default:
// Data content line
excelMediumData.allRowItemList.Add(datas);
// Comment line number
if(string.IsNullOrEmpty(datas[0]) || datas[0].StartsWith(annotationSign))
excelMediumData.annotationRowList.Add(excelMediumData.allRowItemList.Count - 1);
break;
}
//
curRowIndex++;
}
if(CheckExcelMediumData(ref excelMediumData))
{
Debug.Log(" Read Excel success ");
return excelMediumData;
}
else
{
Debug.LogError(" Read Excel Failure ");
return null;
}
}
// check Excel data
private static bool CheckExcelMediumData(ref ExcelMediumData mediumData)
{
if(mediumData == null)
return false;
// Check data validity
if(!mediumData.isValid)
{
Debug.LogError("Excel Marked invalid ");
return false;
}
if(string.IsNullOrEmpty(mediumData.excelName))
{
Debug.LogError("Excel The name is empty. ");
return false;
}
if(mediumData.propertyNameArray == null || mediumData.propertyNameArray.Length == 0)
{
Debug.LogError(" Data name not resolved ");
return false;
}
if(mediumData.propertyTypeArray == null || mediumData.propertyTypeArray.Length == 0)
{
Debug.LogError(" Not resolved to data type ");
return false;
}
if(mediumData.propertyNameArray.Length != mediumData.propertyTypeArray.Length)
{
Debug.LogError(" The data name is inconsistent with the number of data types ");
return false;
}
if(mediumData.allRowItemList.Count == 0)
{
Debug.LogError(" The data content is empty ");
return false;
}
if(mediumData.propertyNameArray[0] != "id")
{
Debug.LogError(" The first field must be id Field ");
return false;
}
return true;
}
#endregion
}
C# Code generation class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;
using System.Linq;
using System;
public class ExcelCodeCreater
{
// Create code , Generate the data C# class
public static string CreateCodeStrByExcelData(ExcelMediumData excelMediumData)
{
if(excelMediumData == null)
return null;
// Row data class name
string itemClassName = excelMediumData.excelName + "ExcelItem";
// Overall data class name
string dataClassName = excelMediumData.excelName + "ExcelData";
// Start generating classes
StringBuilder classSource = new StringBuilder();
classSource.AppendLine("/*Auto Create, Don't Edit !!!*/");
classSource.AppendLine();
// Add reference
classSource.AppendLine("using UnityEngine;");
classSource.AppendLine("using System.Collections.Generic;");
classSource.AppendLine("using System;");
classSource.AppendLine("using System.IO;");
classSource.AppendLine();
// Generate CSharp Data class
if(excelMediumData.isCreateCSharp)
{
// Generate row data class , Record each line of data
classSource.AppendLine(CreateExcelRowItemClass(itemClassName,excelMediumData));
classSource.AppendLine();
// Generate overall data class , Record the whole Excel All rows of data
classSource.AppendLine(CreateExcelAllDataClass(dataClassName,itemClassName,excelMediumData));
classSource.AppendLine();
}
// Generate Asset Create a class
if(excelMediumData.isCreateAssignment)
{
// Generate Asset Operation class , For automatic creation of Excel Corresponding Asset File and assign
classSource.AppendLine(CreateExcelAssetClass(excelMediumData));
classSource.AppendLine();
}
//
return classSource.ToString();
}
//----------
// Generate row data class
private static string CreateExcelRowItemClass(string itemClassName,ExcelMediumData excelMediumData)
{
// Generate Excel Row data class
StringBuilder classSource = new StringBuilder();
// Class name
classSource.AppendLine("[Serializable]");
classSource.AppendLine($"public class {itemClassName} : ExcelItemBase");
classSource.AppendLine("{");
// Declare all fields
for(int i = 0; i < excelMediumData.propertyNameArray.Length; i++)
{
// Skip comment field
if(excelMediumData.annotationColList.Contains(i))
continue;
// Add notes
if(i < excelMediumData.propertyNodeArray.Length)
{
string propertyNode = excelMediumData.propertyNodeArray[i];
if(!string.IsNullOrEmpty(propertyNode))
{
classSource.AppendLine("\t/// <summary>");
classSource.AppendLine($"\t/// {propertyNode}");
classSource.AppendLine("\t/// </summary>>");
}
}
// Declare the fields of the row data class
string propertyName = excelMediumData.propertyNameArray[i];
string propertyType = excelMediumData.propertyTypeArray[i];
string typeStr = GetPropertyType(propertyType);
classSource.AppendLine($"\tpublic {typeStr} {propertyName};");
}
classSource.AppendLine("}");
return classSource.ToString();
}
//----------
// Generate overall data class
private static string CreateExcelAllDataClass(string dataClassName,string itemClassName,ExcelMediumData excelMediumData)
{
StringBuilder classSource = new StringBuilder();
// Class name
classSource.AppendLine($"public class {dataClassName} : ExcelDataBase<{itemClassName}>");
classSource.AppendLine("{");
// Declaration field , Row data class array
classSource.AppendLine($"\tpublic {itemClassName}[] items;");
classSource.AppendLine();
//id Field type
string idTypeStr = GetPropertyType(excelMediumData.propertyTypeArray[0]);
// Declaration Dictionary
classSource.AppendLine($"\tpublic Dictionary<{idTypeStr},{itemClassName}> itemDic = new Dictionary<{idTypeStr},{itemClassName}>();");
classSource.AppendLine();
// Field initialization method
classSource.AppendLine("\tpublic void Init()");
classSource.AppendLine("\t{");
classSource.AppendLine("\t\titemDic.Clear();");
classSource.AppendLine("\t\tif(items != null && items.Length > 0)");
classSource.AppendLine("\t\t{");
classSource.AppendLine("\t\t\tfor(int i = 0; i < items.Length; i++)");
classSource.AppendLine("\t\t\t{");
classSource.AppendLine("\t\t\t\titemDic.Add(items[i].id, items[i]);");
classSource.AppendLine("\t\t\t}");
classSource.AppendLine("\t\t}");
classSource.AppendLine("\t}");
classSource.AppendLine();
// Dictionary acquisition method
classSource.AppendLine($"\tpublic {itemClassName} Get{itemClassName}({idTypeStr} id)");
classSource.AppendLine("\t{");
classSource.AppendLine("\t\tif(itemDic.ContainsKey(id))");
classSource.AppendLine("\t\t\treturn itemDic[id];");
classSource.AppendLine("\t\telse");
classSource.AppendLine("\t\t\treturn null;");
classSource.AppendLine("\t}");
// Each field Get function
classSource.AppendLine("\t#region --- Get Method ---");
classSource.AppendLine();
for(int i = 1; i < excelMediumData.propertyNameArray.Length; i++)
{
if(excelMediumData.annotationColList.Contains(i))
continue;
string propertyName = excelMediumData.propertyNameArray[i];
string propertyType = excelMediumData.propertyTypeArray[i];
// Each field Get function
classSource.AppendLine(CreateCodePropertyMethod(itemClassName,idTypeStr,propertyName,propertyType));
}
classSource.AppendLine("\t#endregion");
classSource.AppendLine("}");
return classSource.ToString();
}
// The generated data field corresponds to Get Method
private static string CreateCodePropertyMethod(string itemClassName,string idTypeStr,string propertyName,string propertyType)
{
StringBuilder methodBuilder = new StringBuilder();
string itemNameStr = propertyName.FirstOrDefault().ToString().ToUpper() + propertyName.Substring(1);
string itemTypeStr = GetPropertyType(propertyType);
// Field Get function
methodBuilder.AppendLine($"\tpublic {itemTypeStr} Get{itemNameStr}({idTypeStr} id)");
methodBuilder.AppendLine("\t{");
methodBuilder.AppendLine($"\t\tvar item = Get{itemClassName}(id);");
methodBuilder.AppendLine("\t\tif(item == null)");
methodBuilder.AppendLine("\t\t\treturn default;");
methodBuilder.AppendLine($"\t\treturn item.{propertyName};");
methodBuilder.AppendLine("\t}");
// If it's a one-dimensional array
if(propertyType.Contains("[]"))
{
//typeStr:int[] or IntArr[] , Return value :int or IntArr
//string itemTypeStr1d = GetPropertyType(propertyType.Replace("[]",""));
string itemTypeStr1d = itemTypeStr.Replace("[]","");
methodBuilder.AppendLine($"\tpublic {itemTypeStr1d} Get{itemNameStr}({idTypeStr} id, int index)");
methodBuilder.AppendLine("\t{");
methodBuilder.AppendLine($"\t\tvar item0 = Get{itemClassName} (id);");
methodBuilder.AppendLine("\t\tif(item0 == null)");
methodBuilder.AppendLine("\t\t\treturn default;");
methodBuilder.AppendLine($"\t\tvar item1 = item0.{propertyName};");
methodBuilder.AppendLine("\t\tif(item1 == null || index < 0 || index >= item1.Length)");
methodBuilder.AppendLine("\t\t\treturn default;");
methodBuilder.AppendLine("\t\treturn item1[index];");
methodBuilder.AppendLine("\t}");
}
// If it's a two-dimensional array
if(propertyType.Contains("[][]"))
{
//propertyType:int[][], Return value :int
string itemTypeStr1d = GetPropertyType(propertyType.Replace("[][]",""));
methodBuilder.AppendLine($"\tpublic {itemTypeStr1d} Get{itemNameStr}({idTypeStr} id, int index1, int index2)");
methodBuilder.AppendLine("\t{");
methodBuilder.AppendLine($"\t\tvar item0 = Get{itemClassName}(id);");
methodBuilder.AppendLine("\t\tif(item0 == null)");
methodBuilder.AppendLine("\t\t\treturn default;");
methodBuilder.AppendLine($"\t\tvar item1 = item0.{propertyName};");
methodBuilder.AppendLine("\t\tif(item1 == null || index1 < 0 || index1 >= item1.Length)");
methodBuilder.AppendLine("\t\t\treturn default;");
methodBuilder.AppendLine("\t\tvar item2 = item1[index1];");
methodBuilder.AppendLine("\t\tif(item2.array == null || index2 < 0 || index2 >= item2.array.Length)");
methodBuilder.AppendLine("\t\t\treturn default;");
methodBuilder.AppendLine("\t\treturn item2.array[index2];");
methodBuilder.AppendLine("\t}");
}
//
return methodBuilder.ToString();
}
//----------
// Generate Asset Create a class
private static string CreateExcelAssetClass(ExcelMediumData excelMediumData)
{
string itemClassName = excelMediumData.excelName + "ExcelItem";
string dataClassName = excelMediumData.excelName + "ExcelData";
string assignmentClassName = excelMediumData.excelName + "AssetAssignment";
StringBuilder classSource = new StringBuilder();
classSource.AppendLine("#if UNITY_EDITOR");
// Class name
classSource.AppendLine($"public class {assignmentClassName}");
classSource.AppendLine("{");
// Method name
classSource.AppendLine("\tpublic static bool CreateAsset(ExcelMediumData excelMediumData, string excelAssetPath)");
// Method body , If necessary, you can join try/catch
classSource.AppendLine("\t{");
classSource.AppendLine("\t\tvar allRowItemDicList = excelMediumData.GetAllRowItemDicList();");
classSource.AppendLine("\t\tif(allRowItemDicList == null || allRowItemDicList.Count == 0)");
classSource.AppendLine("\t\t\treturn false;");
classSource.AppendLine();
classSource.AppendLine("\t\tint rowCount = allRowItemDicList.Count;");
classSource.AppendLine($"\t\t{dataClassName} excelDataAsset = ScriptableObject.CreateInstance<{dataClassName}>();");
classSource.AppendLine($"\t\texcelDataAsset.items = new {itemClassName}[rowCount];");
classSource.AppendLine();
classSource.AppendLine("\t\tfor(int i = 0; i < rowCount; i++)");
classSource.AppendLine("\t\t{");
classSource.AppendLine("\t\t\tvar itemRowDic = allRowItemDicList[i];");
classSource.AppendLine($"\t\t\texcelDataAsset.items[i] = new {itemClassName}();");
for(int i = 0; i < excelMediumData.propertyNameArray.Length; i++)
{
if(excelMediumData.annotationColList.Contains(i))
continue;
string propertyName = excelMediumData.propertyNameArray[i];
string propertyType = excelMediumData.propertyTypeArray[i];
classSource.Append($"\t\t\texcelDataAsset.items[i].{propertyName} = ");
classSource.Append(AssignmentCodeProperty(propertyName,propertyType));
classSource.AppendLine(";");
}
classSource.AppendLine("\t\t}");
classSource.AppendLine("\t\tif(!Directory.Exists(excelAssetPath))");
classSource.AppendLine("\t\t\tDirectory.CreateDirectory(excelAssetPath);");
classSource.AppendLine($"\t\tstring fullPath = Path.Combine(excelAssetPath,typeof({dataClassName}).Name) + \".asset\";");
classSource.AppendLine("\t\tUnityEditor.AssetDatabase.DeleteAsset(fullPath);");
classSource.AppendLine("\t\tUnityEditor.AssetDatabase.CreateAsset(excelDataAsset,fullPath);");
classSource.AppendLine("\t\tUnityEditor.AssetDatabase.Refresh();");
classSource.AppendLine("\t\treturn true;");
classSource.AppendLine("\t}");
//
classSource.AppendLine("}");
classSource.AppendLine("#endif");
return classSource.ToString();
}
// Statement Asset Operation field
private static string AssignmentCodeProperty(string propertyName,string propertyType)
{
string stringValue = $"itemRowDic[\"{propertyName}\"]";
string typeStr = GetPropertyType(propertyType);
switch(typeStr)
{
// Field
case "int":
return "StringUtility.StringToInt(" + stringValue + ")";
case "float":
return "StringUtility.StringToFloat(" + stringValue + ")";
case "bool":
return "StringUtility.StringToBool(" + stringValue + ")";
case "Vector2":
return "StringUtility.StringToVector2(" + stringValue + ")";
case "Vector3":
return "StringUtility.StringToVector3(" + stringValue + ")";
case "Vector2Int":
return "StringUtility.StringToVector2Int(" + stringValue + ")";
case "Vector3Int":
return "StringUtility.StringToVector3Int(" + stringValue + ")";
case "Color":
return "StringUtility.StringToColor(" + stringValue + ")";
case "Color32":
return "StringUtility.StringToColor32(" + stringValue + ")";
case "string":
return stringValue;
// A one-dimensional
case "int[]":
return "StringUtility.StringToIntArray(" + stringValue + ")";
case "float[]":
return "StringUtility.StringToFloatArray(" + stringValue + ")";
case "bool[]":
return "StringUtility.StringToBoolArray(" + stringValue + ")";
case "Vector2[]":
return "StringUtility.StringToVector2Array(" + stringValue + ")";
case "Vector3[]":
return "StringUtility.StringToVector3Array(" + stringValue + ")";
case "Vector2Int[]":
return "StringUtility.StringToVector2IntArray(" + stringValue + ")";
case "Vector3Int[]":
return "StringUtility.StringToVector3IntArray(" + stringValue + ")";
case "Color[]":
return "StringUtility.StringToColorArray(" + stringValue + ")";
case "Color32[]":
return "StringUtility.StringToColor32Array(" + stringValue + ")";
case "string[]":
return "StringUtility.StringToStringArray(" + stringValue + ")";
// A two-dimensional
case "IntArr[]":
return "StringUtility.StringToIntArray2D(" + stringValue + ")";
case "FloatArr[]":
return "StringUtility.StringToFloatArray2D(" + stringValue + ")";
case "BoolArr[]":
return "StringUtility.StringToBoolArray2D(" + stringValue + ")";
case "Vector2Arr[]":
return "StringUtility.StringToVector2Array2D(" + stringValue + ")";
case "Vector3Arr[]":
return "StringUtility.StringToVector3Array2D(" + stringValue + ")";
case "Vector2IntArr[]":
return "StringUtility.StringToVector2IntArray2D(" + stringValue + ")";
case "Vector3IntArr[]":
return "StringUtility.StringToVector3IntArray2D(" + stringValue + ")";
case "ColorArr[]":
return "StringUtility.StringToColorArray2D(" + stringValue + ")";
case "Color32Arr[]":
return "StringUtility.StringToColor32Array2D(" + stringValue + ")";
case "StringArr[]":
return "StringUtility.StringToStringArray2D(" + stringValue + ")";
default:
// enumeration
if(propertyType.StartsWith("enum"))
{
string enumType = propertyType.Split('|').FirstOrDefault();
string enumName = propertyType.Split('|').LastOrDefault();
if(enumType == "enum")
return "StringUtility.StringToEnum<" + enumName + ">(" + stringValue + ")";
else if(enumType == "enum[]")
return "StringUtility.StringToEnumArray<" + enumName + ">(" + stringValue + ")";
else if(enumType == "enum[][]")
return "StringUtility.StringToEnumArray2D<" + enumName + ">(" + stringValue + ")";
}
return stringValue;
}
}
// Determine the field type
private static string GetPropertyType(string propertyType)
{
string lowerType = propertyType.ToLower();
switch(lowerType)
{
case "int":
return "int";
case "int[]":
return "int[]";
case "int[][]":
return "IntArr[]";
case "float":
return "float";
case "float[]":
return "float[]";
case "float[][]":
return "FloatArr[]";
case "bool":
return "bool";
case "bool[]":
return "bool[]";
case "bool[][]":
return "BoolArr[]";
case "string":
return "string";
case "string[]":
return "string[]";
case "string[][]":
return "StringArr[]";
case "vector2":
return "Vector2";
case "vector2[]":
return "Vector2[]";
case "vector2[][]":
return "Vector2Arr[]";
case "vector2int":
return "Vector2Int";
case "vector2int[]":
return "Vector2Int[]";
case "vector2int[][]":
return "Vector2IntArr[]";
case "vector3":
return "Vector3";
case "vector3[]":
return "Vector3[]";
case "vector3[][]":
return "Vector3Arr[]";
case "vector3int":
return "Vector3Int";
case "vector3int[]":
return "Vector3Int[]";
case "vector3int[][]":
return "Vector3IntArr[]";
case "color":
return "Color";
case "color[]":
return "Color[]";
case "color[][]":
return "ColorArr[]";
case "color32":
return "Color32";
case "color32[]":
return "Color32[]";
case "color32[][]":
return "Color32Arr[]";
default:
if(propertyType.StartsWith("enum"))
{
string enumType = propertyType.Split('|').FirstOrDefault();
string enumName = propertyType.Split('|').LastOrDefault();
switch(enumType)
{
case "enum":
return enumName;
case "enum[]":
return $"{enumName}[]";
case "enum[][]":
return $"EnumArr<{enumName}>[]";
default:
break;
}
}
return "string";
}
}
}
Excel Data intermediate class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Excel Intermediate data
public class ExcelMediumData
{
//Excel name
public string excelName;
//Excel Whether it works
public bool isValid = false;
// Whether to generate CSharp Data class
public bool isCreateCSharp = false;
// Whether to generate Asset Create a class
public bool isCreateAssignment = false;
// Whether to generate Asset file
public bool isCreateAsset = false;
// Data annotation
public string[] propertyNodeArray = null;
// Data name
public string[] propertyNameArray = null;
// data type
public string[] propertyTypeArray = null;
//List< Data content of each line >
public List<string[]> allRowItemList = new List<string[]>();
// Comment line number
public List<int> annotationRowList = new List<int>();
// Comment column number
public List<int> annotationColList = new List<int>();
//List< Each line of data >,List<Dictionary< Cell field name , Cell field value >>
public List<Dictionary<string,string>> GetAllRowItemDicList()
{
if(propertyNameArray == null || propertyNameArray.Length == 0)
return null;
if(allRowItemList.Count == 0)
return null;
List<Dictionary<string,string>> allRowItemDicList = new List<Dictionary<string,string>>(allRowItemList.Count);
for(int i = 0; i < allRowItemList.Count; i++)
{
string[] rowArray = allRowItemList[i];
// Skip empty data
if(rowArray == null || rowArray.Length == 0)
continue;
// Skip annotation data
if(annotationRowList.Contains(i))
continue;
// Each line of data , Corresponding field name and field value
Dictionary<string,string> rowDic = new Dictionary<string,string>();
for(int j = 0; j < propertyNameArray.Length; j++)
{
// Skip comment field
if(annotationColList.Contains(j))
continue;
string propertyName = propertyNameArray[j];
string propertyValue = j < rowArray.Length ? rowArray[j] : null;
rowDic[propertyName] = propertyValue;
}
allRowItemDicList.Add(rowDic);
}
return allRowItemDicList;
}
}
Excel Data base class 、 The extension class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System;
public class ExcelDataBase<T> : ScriptableObject where T : ExcelItemBase
{
}
public class ExcelItemBase
{
}
[Serializable]
public struct StringArr
{
public string[] array;
}
[Serializable]
public struct IntArr
{
public int[] array;
}
[Serializable]
public struct FloatArr
{
public float[] array;
}
[Serializable]
public struct BoolArr
{
public bool[] array;
}
[Serializable]
public struct Vector2Arr
{
public Vector2[] array;
}
[Serializable]
public struct Vector3Arr
{
public Vector3[] array;
}
[Serializable]
public struct Vector2IntArr
{
public Vector2Int[] array;
}
[Serializable]
public struct Vector3IntArr
{
public Vector3Int[] array;
}
[Serializable]
public struct ColorArr
{
public Color[] array;
}
[Serializable]
public struct Color32Arr
{
public Color32[] array;
}
//// Generic enumeration serialization is not supported
//[Serializable]
//public struct EnumArr<T> where T : Enum
//{
// public T[] array;
//}
String utility class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text.RegularExpressions;
using System;
using System.Text;
using System.Linq;
using System.Runtime.CompilerServices;
public static class StringUtility
{
#region --- AddColor ---
public static string AddColor(object obj,Color color)
{
return AddColor(obj,color);
}
public static string AddColor(this string str,Color color)
{
// Convert the color to 16 Base string , Add to rich text
return string.Format("<color=#{0}>{1}</color>",ColorUtility.ToHtmlStringRGBA(color),str);
}
public static string AddColor(string str1,string str2,Color color)
{
return AddColor(str1 + str2,color);
}
public static string AddColor(string str1,string str2,string str3,Color color)
{
return AddColor(str1 + str2 + str3,color);
}
#endregion
#region --- string length ---
/// <summary>
/// Reduce string length
/// </summary>
/// <param name="targetStr"></param>
/// <param name="targetLength"> Target length , English characters ==1, Chinese characters ==2</param>
/// <returns></returns>
public static string AbbrevStringWithinLength(string targetStr,int targetLength,string abbrevPostfix)
{
//C# Actual statistics : The length of a Chinese character ==1, English character length ==1
//UI Display requirements : The length of a Chinese character ==2, English character length ==1
// Calibration parameters
if(string.IsNullOrEmpty(targetStr) || targetLength <= 0)
return targetStr;
// String length * 2 <= Target length , Even if it is all Chinese, it is within the length range
if(targetStr.Length * 2 <= targetLength)
return targetStr;
// Traversal character
char[] chars = targetStr.ToCharArray();
int curLen = 0;
for(int i = 0; i < chars.Length; i++)
{
// Accumulate string length
if(chars[i] >= 0x4e00 && chars[i] <= 0x9fbb)
curLen += 2;
else
curLen += 1;
// If the cumulative length of the current position exceeds the target length , take 0~i-1, namely Substring(0,i)
if(curLen > targetLength)
return targetStr.Substring(0,i) + abbrevPostfix;
}
return targetStr;
}
#endregion
#region --- String To Array ---
//string
public static byte StringToByte(string valueStr)
{
byte value;
if(byte.TryParse(valueStr,out value))
return value;
else
return 0;
}
public static string[] StringToStringArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
return valueStr.Split(splitSign);
}
public static StringArr[] StringToStringArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
StringArr[] arrArr = new StringArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new StringArr()
{
array = strArr1[i].Split(splitSign2)
};
}
return arrArr;
}
//int
public static int StringToInt(string valueStr)
{
int value;
if(int.TryParse(valueStr,out value))
return value;
else
return 0;
}
public static int[] StringToIntArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] valueArr = valueStr.Split(splitSign);
if(valueArr == null || valueArr.Length == 0)
return null;
int[] intArr = new int[valueArr.Length];
for(int i = 0; i < valueArr.Length; i++)
{
intArr[i] = StringToInt(valueArr[i]);
}
return intArr;
}
public static IntArr[] StringToIntArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
IntArr[] arrArr = new IntArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new IntArr()
{
array = StringToIntArray(strArr1[i],splitSign2)
};
}
return arrArr;
}
//float
public static float StringToFloat(string valueStr)
{
float value;
if(float.TryParse(valueStr,out value))
return value;
else
return 0;
}
public static float[] StringToFloatArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] valueArr = valueStr.Split(splitSign);
if(valueArr == null || valueArr.Length == 0)
return null;
float[] floatArr = new float[valueArr.Length];
for(int i = 0; i < valueArr.Length; i++)
{
floatArr[i] = StringToFloat(valueArr[i]);
}
return floatArr;
}
public static FloatArr[] StringToFloatArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
FloatArr[] arrArr = new FloatArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new FloatArr()
{
array = StringToFloatArray(strArr1[i],splitSign2)
};
}
return arrArr;
}
//bool
public static bool StringToBool(string valueStr)
{
bool value;
if(bool.TryParse(valueStr,out value))
return value;
else
return false;
}
public static bool[] StringToBoolArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] valueArr = valueStr.Split(splitSign);
if(valueArr == null || valueArr.Length == 0)
return null;
bool[] boolArr = new bool[valueArr.Length];
for(int i = 0; i < valueArr.Length; i++)
{
boolArr[i] = StringToBool(valueArr[i]);
}
return boolArr;
}
public static BoolArr[] StringToBoolArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
BoolArr[] arrArr = new BoolArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new BoolArr()
{
array = StringToBoolArray(strArr1[i],splitSign2)
};
}
return arrArr;
}
//enum
public static T StringToEnum<T>(string valueStr) where T : Enum
{
if(string.IsNullOrEmpty(valueStr))
return (T)default;
// First verify whether the string is an enumeration value
int intValue;
if(int.TryParse(valueStr,out intValue))
{
if(Enum.IsDefined(typeof(T),intValue))
return (T)Enum.ToObject(typeof(T),intValue);
}
// If it is not an enumerated value , Treat as enum name
try
{
T t = (T)Enum.Parse(typeof(T),valueStr);
if(Enum.IsDefined(typeof(T),t))
return t;
}
catch(Exception e)
{
Debug.LogError(e);
}
Debug.LogError(string.Format(" Parsing enumeration error {0} : {1}",typeof(T),valueStr));
return (T)default;
}
public static T[] StringToEnumArray<T>(string valueStr,char splitSign = '|') where T : Enum
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] valueArr = valueStr.Split(splitSign);
if(valueArr == null || valueArr.Length == 0)
return null;
T[] enumArr = new T[valueArr.Length];
for(int i = 0; i < valueArr.Length; i++)
{
enumArr[i] = StringToEnum<T>(valueArr[i]);
}
return enumArr;
}
//// Generic enumeration serialization is not supported
//public static EnumArr<T>[] StringToEnumArray2D<T>(string valueStr,char splitSign1 = '&',char splitSign2 = '|') where T : Enum
//{
// if(string.IsNullOrEmpty(valueStr))
// return null;
// string[] strArr1 = valueStr.Split(splitSign1);
// if(strArr1.Length == 0)
// return null;
// EnumArr<T>[] arrArr = new EnumArr<T>[strArr1.Length];
// for(int i = 0; i < strArr1.Length; i++)
// {
// arrArr[i] = new EnumArr<T>()
// {
// array = StringToEnumArray<T>(strArr1[i],splitSign2)
// };
// }
// return arrArr;
//}
//vector2
public static Vector2 StringToVector2(string valueStr,char splitSign = ',')
{
Vector2 value = Vector2.zero;
if(!string.IsNullOrEmpty(valueStr))
{
string[] stringArray = valueStr.Split(splitSign);
if(stringArray != null && stringArray.Length >= 2)
{
value.x = StringToFloat(stringArray[0]);
value.y = StringToFloat(stringArray[1]);
return value;
}
}
Debug.LogWarning("String to Vector2 error");
return value;
}
public static Vector2[] StringToVector2Array(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray == null || stringArray.Length == 0)
return null;
Vector2[] vector2s = new Vector2[stringArray.Length];
for(int i = 0; i < stringArray.Length; i++)
{
vector2s[i] = StringToVector2(stringArray[i]);
}
return vector2s;
}
public static Vector2Arr[] StringToVector2Array2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
Vector2Arr[] arrArr = new Vector2Arr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new Vector2Arr()
{
array = StringToVector2Array(strArr1[i],splitSign2)
};
}
return arrArr;
}
//vector3
public static Vector3 StringToVector3(string valueStr,char splitSign = ',')
{
Vector3 value = Vector3.zero;
if(!string.IsNullOrEmpty(valueStr))
{
string[] stringArray = valueStr.Split(splitSign);
if(stringArray.Length >= 3)
{
value.x = StringToFloat(stringArray[0]);
value.y = StringToFloat(stringArray[1]);
value.z = StringToFloat(stringArray[2]);
return value;
}
}
Debug.LogWarning("String to Vector3 error");
return value;
}
public static Vector3[] StringToVector3Array(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray == null || stringArray.Length == 0)
return null;
Vector3[] vector3s = new Vector3[stringArray.Length];
for(int i = 0; i < stringArray.Length; i++)
{
vector3s[i] = StringToVector3(stringArray[i]);
}
return vector3s;
}
public static Vector3Arr[] StringToVector3Array2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
Vector3Arr[] arrArr = new Vector3Arr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new Vector3Arr()
{
array = StringToVector3Array(strArr1[i],splitSign2)
};
}
return arrArr;
}
//vector2Int
public static Vector2Int StringToVector2Int(string valueStr,char splitSign = ',')
{
Vector2Int value = Vector2Int.zero;
if(!string.IsNullOrEmpty(valueStr))
{
string[] stringArray = valueStr.Split(splitSign);
if(stringArray != null && stringArray.Length >= 2)
{
value.x = StringToInt(stringArray[0]);
value.y = StringToInt(stringArray[1]);
return value;
}
}
Debug.LogWarning("String to Vector2Int error");
return value;
}
public static Vector2Int[] StringToVector2IntArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray == null || stringArray.Length == 0)
return null;
Vector2Int[] vector2Ints = new Vector2Int[stringArray.Length];
for(int i = 0; i < stringArray.Length; i++)
{
vector2Ints[i] = StringToVector2Int(stringArray[i]);
}
return vector2Ints;
}
public static Vector2IntArr[] StringToVector2IntArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
Vector2IntArr[] arrArr = new Vector2IntArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new Vector2IntArr()
{
array = StringToVector2IntArray(strArr1[i],splitSign2)
};
}
return arrArr;
}
//vector3Int
public static Vector3Int StringToVector3Int(string valueStr,char splitSign = ',')
{
Vector3Int value = Vector3Int.zero;
if(!string.IsNullOrEmpty(valueStr))
{
string[] stringArray = valueStr.Split(splitSign);
if(stringArray.Length >= 3)
{
value.x = StringToInt(stringArray[0]);
value.y = StringToInt(stringArray[1]);
value.z = StringToInt(stringArray[2]);
return value;
}
}
Debug.LogWarning("String to Vector3 error");
return value;
}
public static Vector3Int[] StringToVector3IntArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray == null || stringArray.Length == 0)
return null;
Vector3Int[] vector3Ints = new Vector3Int[stringArray.Length];
for(int i = 0; i < stringArray.Length; i++)
{
vector3Ints[i] = StringToVector3Int(stringArray[i]);
}
return vector3Ints;
}
public static Vector3IntArr[] StringToVector3IntArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
Vector3IntArr[] arrArr = new Vector3IntArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new Vector3IntArr()
{
array = StringToVector3IntArray(strArr1[i],splitSign2)
};
}
return arrArr;
}
//color
public static Color StringToColor(string valueStr,char splitSign = ',')
{
if(string.IsNullOrEmpty(valueStr))
return Color.white;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray.Length < 3)
return Color.white;
Color color = new Color()
{
r = StringToFloat(stringArray[0]),
g = StringToFloat(stringArray[1]),
b = StringToFloat(stringArray[2]),
a = stringArray.Length < 4 ? 1 : StringToFloat(stringArray[3])
};
return color;
}
public static Color32 StringToColor32(string valueStr,char splitSign = ',')
{
if(string.IsNullOrEmpty(valueStr))
return Color.white;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray.Length < 3)
return Color.white;
Color32 color = new Color32()
{
r = StringToByte(stringArray[0]),
g = StringToByte(stringArray[1]),
b = StringToByte(stringArray[2]),
a = stringArray.Length < 4 ? (byte)1 : StringToByte(stringArray[3])
};
return color;
}
public static Color[] StringToColorArray(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray == null || stringArray.Length == 0)
return null;
Color[] colors = new Color[stringArray.Length];
for(int i = 0; i < stringArray.Length; i++)
{
colors[i] = StringToColor(stringArray[i]);
}
return colors;
}
public static Color32[] StringToColor32Array(string valueStr,char splitSign = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] stringArray = valueStr.Split(splitSign);
if(stringArray == null || stringArray.Length == 0)
return null;
Color32[] colors = new Color32[stringArray.Length];
for(int i = 0; i < stringArray.Length; i++)
{
colors[i] = StringToColor32(stringArray[i]);
}
return colors;
}
public static ColorArr[] StringToColorArray2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
ColorArr[] arrArr = new ColorArr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new ColorArr()
{
array = StringToColorArray(strArr1[i],splitSign2)
};
}
return arrArr;
}
public static Color32Arr[] StringToColor32Array2D(string valueStr,char splitSign1 = '&',char splitSign2 = '|')
{
if(string.IsNullOrEmpty(valueStr))
return null;
string[] strArr1 = valueStr.Split(splitSign1);
if(strArr1.Length == 0)
return null;
Color32Arr[] arrArr = new Color32Arr[strArr1.Length];
for(int i = 0; i < strArr1.Length; i++)
{
arrArr[i] = new Color32Arr()
{
array = StringToColor32Array(strArr1[i],splitSign2)
};
}
return arrArr;
}
#endregion
#region MyRegion
public static string GetRandomString(int length)
{
StringBuilder builder = new StringBuilder();
string abc = "abcdefghijklmnopqrstuvwxyzo0123456789QWERTYUIOPASDFGHJKLZXCCVBMN";
for(int i = 0; i < length; i++)
{
builder.Append(abc[UnityEngine.Random.Range(0,abc.Length - 1)]);
}
return builder.ToString();
}
public static string Join<T>(T[] arr,string join = ",")
{
if(arr == null || arr.Length == 0)
return null;
StringBuilder builder = new StringBuilder();
for(int i = 0; i < arr.Length; i++)
{
builder.Append(arr[i]);
if(i < arr.Length - 1)
builder.Append(join);
}
return builder.ToString();
}
/// <summary>
/// Chinese comma to English comma
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string ToDBC(string input)
{
char[] c = input.ToCharArray();
for(int i = 0; i < c.Length; i++)
{
if(c[i] == 12288)
{
c[i] = (char)32;
continue;
}
if(c[i] > 65280 && c[i] < 65375)
c[i] = (char)(c[i] - 65248);
}
return new string(c);
}
/// <summary>
/// Character conversion ascii code
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
public static int Asc(string character)
{
if(character.Length == 1)
{
System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
int intAsciiCode = (int)asciiEncoding.GetBytes(character)[0];
return (intAsciiCode);
}
Debug.LogError("Character is not valid.");
return -1;
}
/// <summary>
/// ascii Code to character
/// </summary>
/// <param name="asciiCode"></param>
/// <returns></returns>
public static string Chr(int asciiCode)
{
if(asciiCode >= 0 && asciiCode <= 255)
{
System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
byte[] byteArray = new byte[] { (byte)asciiCode };
string strCharacter = asciiEncoding.GetString(byteArray);
return (strCharacter);
}
Debug.LogError("ASCII Code is not valid.");
return string.Empty;
}
/// <summary>
/// Filter out emoticons
/// </summary>
/// <returns>The emoji.</returns>
/// <param name="str">String.</param>
public static string FilterEmoji(string str)
{
List<string> patten = new List<string>() { @"\p{Cs}",@"\p{Co}",@"\p{Cn}",@"[\u2702-\u27B0]" };
for(int i = 0; i < patten.Count; i++)
{
str = Regex.Replace(str,patten[i],"");// shielding emoji
}
return str;
}
/// <summary>
/// Filter out emoticons
/// </summary>
/// <returns>The emoji.</returns>
/// <param name="str">String.</param>
public static bool IsFilterEmoji(string str)
{
bool bEmoji = false;
List<string> patten = new List<string>() { @"\p{Cs}",@"\p{Co}",@"\p{Cn}",@"[\u2702-\u27B0]" };
for(int i = 0; i < patten.Count; i++)
{
bEmoji = Regex.IsMatch(str,patten[i]);
if(bEmoji)
{
break;
}
}
return bEmoji;
}
#endregion
#region StringObjectDictionaryExtensions
/// <summary>
/// Structure for the following key values contained in the dictionary :mctid0=xxx;mccount0=1,mctid1=kn2,mccount=2. Remove the prefix , The number suffix becomes a key , Such as { suffix ,( Remove the key before the suffix , value )}, Note that the suffix may be an empty string, that is, there is no suffix
/// </summary>
/// <param name="dic"></param>
/// <param name="prefix"> Prefix , It can be an empty reference or an empty string , Means there is no prefix .</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IEnumerable<IGrouping<string,(string, object)>> GetValuesWithoutPrefix(this IReadOnlyDictionary<string,object> dic,string prefix = null)
{
//prefix ??= string.Empty;
prefix = prefix ?? string.Empty;
var coll = from tmp in dic.Where(c => c.Key.StartsWith(prefix)) // Only for the key value of the specified prefix
let p3 = tmp.Key.Get3Segment(prefix)
group (p3.Item2, tmp.Value) by p3.Item3;
return coll;
}
/// <summary>
/// Break the string into three segments , Prefix , Root , number suffix ( String form ).
/// </summary>
/// <param name="str"></param>
/// <param name="prefix"> Prefix , It can be an empty reference or an empty string , Means there is no prefix .</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static (string, string, string) Get3Segment(this string str,string prefix = null)
{
//prefix ??= string.Empty;
prefix = prefix ?? string.Empty;
// The length of the last decimal digit tail string
int suffixLen = Enumerable.Reverse(str).TakeWhile(c => char.IsDigit(c)).Count();
// Get decimal digit suffix
//string suufix = str[^suffixLen..]; //^suffixLen: Reverse subscript ;suffixLen..: From the specified position to the end
string suufix = str.Substring(str.Length - suffixLen);
//return (prefix, str[prefix.Length..^suufix.Length], suufix);
string middle = str.Substring(prefix.Length,str.Length - prefix.Length - suufix.Length);
return (prefix, middle, suufix);
}
#endregion
}
Demo link :
边栏推荐
- How to achieve text animation effect
- OpenSSL: a full-featured toolkit for TLS and SSL protocols, and a general encryption library
- 使用云服务器搭建代理
- The ceiling of MySQL tutorial. Collect it and take your time
- [compilation principle] LR (0) analyzer half done
- 2014阿里巴巴web前实习生项目分析(1)
- 服务器的系统怎么选者
- Motion capture for snake motion analysis and snake robot development
- AdaViT——自适应选择计算结构的动态网络
- 浅谈网络安全之文件上传
猜你喜欢
Leetcode exercise - Sword finger offer 26 Substructure of tree
CSDN 上传图片取消自动加水印的方法
动作捕捉用于蛇运动分析及蛇形机器人开发
浅谈网络安全之文件上传
Should novice programmers memorize code?
Aardio - construct a multi button component with customplus library +plus
Sword finger offer question brushing record 1
Dayu200 experience officer runs the intelligent drying system page based on arkui ETS on dayu200
Export MySQL table data in pure mode
Matlab tips (27) grey prediction
随机推荐
How to achieve text animation effect
Export MySQL table data in pure mode
Pit encountered by handwritten ABA
UDP编程
C# 三种方式实现Socket数据接收
POJ 1258 Agri-Net
Method of canceling automatic watermarking of uploaded pictures by CSDN
European Bioinformatics Institute 2021 highlights report released: nearly 1million proteins have been predicted by alphafold
OpenNMS分离数据库
How to confirm the storage mode of the current system by program?
云原生技术--- 容器知识点
SQL server generates auto increment sequence number
Introduction to network basics
MySQL authentication bypass vulnerability (cve-2012-2122)
Leetcode: interview question 17.24 Maximum cumulative sum of submatrix (to be studied)
leetcode:面试题 17.24. 子矩阵最大累加和(待研究)
CocosCreator+TypeScripts自己写一个对象池
Signed and unsigned keywords
【无标题】
OpenSSL:适用TLS与SSL协议的全功能工具包,通用加密库