当前位置:网站首页>[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-07 02:18:00 【51CTO】
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
Excel Annotation operations :
- 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 :
Row data class , Corresponding to each row of data :
[Serializable]
public class TestConfigExcelItem : ExcelItemBase
{
/// <summary>
///
/// </summary>>
public int id;
/// <summary>
///
/// </summary>>
public string testString;
/// <summary>
///
/// </summary>>
public int testInt;
/// <summary>
///
/// </summary>>
public float
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
Complete data class , Contains all rows of data 、 Initialization function 、Get function :
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)
{
if(itemDic.ContainsKey(id))
return itemDic[id];
else
return null;
}
#region
public string GetTestString(int)
{
var item = GetTestConfigExcelItem(id);
if(item == null)
return default;
return item.testString;
}
// ··· ···
#endregion
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
Currently supported data structures :
character string | testString | Array of strings | testStringArray | Two dimensional array of strings | testStringArray2 |
Int | testInt | Int Array | testIntArray | Int Two dimensional array | testIntArray2 |
Float | testFloat | Float Array | testFloatArray | Float Two dimensional array | testFloatArray2 |
Bool | testBool | Bool Array | testBoolArray | Bool Two dimensional array | testBoolArray2 |
Enum| Enum name ( Or enumeration value ) | testEnum | Enum Array | testEnumArray | Enum Two dimensional array | I won't support it |
Vector2 | testVector2 | Vector2 Array | testVector2Array | Vector2 Two dimensional array | testVector2Array2 |
Vector3 | testVector3 | Vector3 Array | testVector3Array | Vector3 Two dimensional array | testVector3Array2 |
Vector2Int | testVector2Int | Vector2Int Array | testVector2IntArray | Vector2Int Two dimensional array | testVector2IntArray2 |
Vector3Int | testVector3Int | Vector3Int Array | testVector3IntArray | Vector3Int Two dimensional array | testVector3IntArray2 |
Color | testColor | Color Array | testColorArray | Color Two dimensional array | testColorArray2 |
Color32 | testColor32 | Color32 Array | testColor32Array | Color32 Two dimensional array | testColor32Array2 |
because Unity Cannot serialize a two-dimensional array , Here it is changed to a one-dimensional array + Structure is realized :
Asset Data files :
In the process of automatically generating data C# Class time , Will be generated synchronously Asset File creation class , For automatic creation of Asset File and serialize data .
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)
{
Object targetObj = AssetDatabase.LoadAssetAtPath<Object>(targetPath);
EditorGUIUtility.PingObject(targetObj);
Selection.activeObject = targetObj;
Debug.Log(targetPath);
}
private static string CheckEditorPath(string)
{
#if
return path.Replace("/","\\");
#elif
return path.Replace("\\","/");
#else
return path;
#endif
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
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
// establish Excel Corresponding C# class
public static void ReadAllExcelToCode(string allExcelPath,string)
{
// 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)
{
// 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
// establish Excel Corresponding Asset Data files
public static void CreateAllExcelAsset(string allExcelPath,string)
{
// 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)
{
// 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
// analysis Excel, Create intermediate data
private static ExcelMediumData CreateClassCodeByExcelPath(string)
{
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)
{
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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
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)
{
// Generate Excel Row data class
StringBuilder classSource = new StringBuilder();
// Class name
classSource.AppendLine("[Serializable]");
classSource.AppendLine($"public class {itemClassName});
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)
{
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});
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)
{
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});
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});
methodBuilder.AppendLine("\t{");
methodBuilder.AppendLine($"\t\tvar item0 = Get{itemClassName});
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});
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)
{
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)
{
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";
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
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;
//}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
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
public static string AddColor(object)
{
return AddColor(obj,color);
}
public static string AddColor(this string)
{
// 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)
{
return AddColor(str1 + str2,color);
}
public static string AddColor(string str1,string str2,string)
{
return AddColor(str1 + str2 + str3,color);
}
#endregion
#region
/// <summary>
///
/// </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)
{
//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
public static byte StringToByte(string)
{
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)
{
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)
{
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)
{
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) where
{
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
{
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
public static string GetRandomString(int)
{
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>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string ToDBC(string)
{
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>
///
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
public static int Asc(string)
{
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>
///
/// </summary>
/// <param name="asciiCode"></param>
/// <returns></returns>
public static string Chr(int)
{
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>
///
/// </summary>
/// <returns>The emoji.</returns>
/// <param name="str">String.</param>
public static string FilterEmoji(string)
{
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>
///
/// </summary>
/// <returns>The emoji.</returns>
/// <param name="str">String.</param>
public static bool IsFilterEmoji(string)
{
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
/// <summary>
///
/// </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>
///
/// </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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
- 439.
- 440.
- 441.
- 442.
- 443.
- 444.
- 445.
- 446.
- 447.
- 448.
- 449.
- 450.
- 451.
- 452.
- 453.
- 454.
- 455.
- 456.
- 457.
- 458.
- 459.
- 460.
- 461.
- 462.
- 463.
- 464.
- 465.
- 466.
- 467.
- 468.
- 469.
- 470.
- 471.
- 472.
- 473.
- 474.
- 475.
- 476.
- 477.
- 478.
- 479.
- 480.
- 481.
- 482.
- 483.
- 484.
- 485.
- 486.
- 487.
- 488.
- 489.
- 490.
- 491.
- 492.
- 493.
- 494.
- 495.
- 496.
- 497.
- 498.
- 499.
- 500.
- 501.
- 502.
- 503.
- 504.
- 505.
- 506.
- 507.
- 508.
- 509.
- 510.
- 511.
- 512.
- 513.
- 514.
- 515.
- 516.
- 517.
- 518.
- 519.
- 520.
- 521.
- 522.
- 523.
- 524.
- 525.
- 526.
- 527.
- 528.
- 529.
- 530.
- 531.
- 532.
- 533.
- 534.
- 535.
- 536.
- 537.
- 538.
- 539.
- 540.
- 541.
- 542.
- 543.
- 544.
- 545.
- 546.
- 547.
- 548.
- 549.
- 550.
- 551.
- 552.
- 553.
- 554.
- 555.
- 556.
- 557.
- 558.
- 559.
- 560.
- 561.
- 562.
- 563.
- 564.
- 565.
- 566.
- 567.
- 568.
- 569.
- 570.
- 571.
- 572.
- 573.
- 574.
- 575.
- 576.
- 577.
- 578.
- 579.
- 580.
- 581.
- 582.
- 583.
- 584.
- 585.
- 586.
- 587.
- 588.
- 589.
- 590.
- 591.
- 592.
- 593.
- 594.
- 595.
- 596.
- 597.
- 598.
- 599.
- 600.
- 601.
- 602.
- 603.
- 604.
- 605.
- 606.
- 607.
- 608.
- 609.
- 610.
- 611.
- 612.
- 613.
- 614.
- 615.
- 616.
- 617.
- 618.
- 619.
- 620.
- 621.
- 622.
- 623.
- 624.
- 625.
- 626.
- 627.
- 628.
- 629.
- 630.
- 631.
- 632.
- 633.
- 634.
- 635.
- 636.
- 637.
- 638.
- 639.
- 640.
- 641.
- 642.
- 643.
- 644.
- 645.
- 646.
- 647.
- 648.
- 649.
- 650.
- 651.
- 652.
- 653.
- 654.
- 655.
- 656.
- 657.
- 658.
- 659.
- 660.
- 661.
- 662.
- 663.
- 664.
- 665.
- 666.
- 667.
- 668.
- 669.
- 670.
- 671.
- 672.
- 673.
- 674.
- 675.
- 676.
- 677.
- 678.
- 679.
- 680.
- 681.
- 682.
- 683.
- 684.
- 685.
- 686.
- 687.
- 688.
- 689.
- 690.
- 691.
- 692.
- 693.
- 694.
- 695.
- 696.
- 697.
- 698.
- 699.
- 700.
- 701.
- 702.
- 703.
- 704.
- 705.
- 706.
- 707.
- 708.
- 709.
- 710.
- 711.
- 712.
- 713.
- 714.
- 715.
- 716.
- 717.
- 718.
- 719.
- 720.
- 721.
- 722.
- 723.
- 724.
- 725.
- 726.
- 727.
- 728.
- 729.
- 730.
- 731.
- 732.
- 733.
- 734.
- 735.
- 736.
- 737.
- 738.
- 739.
- 740.
- 741.
- 742.
- 743.
- 744.
- 745.
- 746.
- 747.
- 748.
- 749.
- 750.
- 751.
- 752.
- 753.
- 754.
- 755.
- 756.
- 757.
- 758.
- 759.
- 760.
- 761.
- 762.
- 763.
- 764.
- 765.
- 766.
- 767.
- 768.
- 769.
- 770.
- 771.
- 772.
- 773.
- 774.
- 775.
- 776.
- 777.
- 778.
- 779.
- 780.
- 781.
- 782.
- 783.
- 784.
- 785.
- 786.
- 787.
- 788.
- 789.
- 790.
- 791.
- 792.
- 793.
- 794.
- 795.
- 796.
- 797.
- 798.
- 799.
- 800.
- 801.
- 802.
- 803.
- 804.
- 805.
- 806.
- 807.
- 808.
- 809.
- 810.
- 811.
- 812.
- 813.
- 814.
- 815.
- 816.
- 817.
- 818.
- 819.
- 820.
- 821.
- 822.
边栏推荐
- A new path for enterprise mid Platform Construction -- low code platform
- STM32F4---通用定时器更新中断
- FLIR blackfly s industrial camera: auto exposure configuration and code
- 如何从0到1构建32Core树莓派集群
- How did partydao turn a tweet into a $200million product Dao in one year
- How to use strings as speed templates- How to use String as Velocity Template?
- PartyDAO如何在1年内把一篇推文变成了2亿美金的产品DAO
- Unicode string converted to Chinese character decodeunicode utils (tool class II)
- Tips for web development: skillfully use ThreadLocal to avoid layer by layer value transmission
- ROS学习(21)机器人SLAM功能包——orbslam的安装与测试
猜你喜欢
Cisp-pte practice explanation (II)
sql中批量删除数据---实体中的集合
BigDecimal 的正确使用方式
阿里云中间件开源往事
ROS學習(23)action通信機制
老板被隔离了
Shell script quickly counts the number of lines of project code
Recommended collection!! Which is the best flutter status management plug-in? Please look at the ranking list of yard farmers on the island!
centos8安裝mysql報錯:The GPG keys listed for the “MySQL 8.0 Community Server“ repository are already ins
传感器:土壤湿度传感器(XH-M214)介绍及stm32驱动代码
随机推荐
遇到慢SQL该怎么办?(下)
Centos8 install MySQL 8.0 using yum x
How can reinforcement learning be used in medical imaging? A review of Emory University's latest "reinforcement learning medical image analysis", which expounds the latest RL medical image analysis co
Integrated navigation: product description and interface description of zhonghaida inav2
新一代云原生消息队列(一)
传感器:DS1302时钟芯片及驱动代码
ROS学习(21)机器人SLAM功能包——orbslam的安装与测试
【论文阅读|深读】 GraphSAGE:Inductive Representation Learning on Large Graphs
ROS学习(22)TF变换
Errors made in the development of merging the quantity of data in the set according to attributes
npm install 编译时报“Cannot read properties of null (reading ‘pickAlgorithm‘)“
Date processing tool class dateutils (tool class 1)
ROS learning (25) rviz plugin
The last line of defense of cloud primary mixing department: node waterline design
STM32F4---通用定时器更新中断
Flir Blackfly S USB3 工业相机:白平衡设置方法
ROS學習(23)action通信機制
Draco - glTF模型压缩利器
Flir Blackfly S 工业相机:通过外部触发实现多摄像头同步拍摄
ZABBIX 5.0: automatically monitor Alibaba cloud RDS through LLD