当前位置:网站首页>[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.
边栏推荐
- Metaforce force meta universe development and construction - fossage 2.0 system development
- PartyDAO如何在1年内把一篇推文变成了2亿美金的产品DAO
- 2022 system integration project management engineer examination knowledge point: Mobile Internet
- Modify the system time of Px4 flight control
- 将截断字符串或二进制数据
- npm install 编译时报“Cannot read properties of null (reading ‘pickAlgorithm‘)“
- The use of video in the wiper component causes full screen dislocation
- Analyze "C language" [advanced] paid knowledge [II]
- Recommended collection!! Which is the best flutter status management plug-in? Please look at the ranking list of yard farmers on the island!
- leetcode:5. 最长回文子串【dp + 抓着超时的尾巴】
猜你喜欢
如何从0到1构建32Core树莓派集群
ROS学习(26)动态参数配置
centos8安装mysql报错:The GPG keys listed for the “MySQL 8.0 Community Server“ repository are already ins
centos8安裝mysql報錯:The GPG keys listed for the “MySQL 8.0 Community Server“ repository are already ins
Introduction to FLIR blackfly s industrial camera
ROS学习(二十)机器人SLAM功能包——rgbdslam的安装与测试
Lumion 11.0软件安装包下载及安装教程
大咖云集|NextArch基金会云开发Meetup来啦!
FLIR blackfly s usb3 industrial camera: white balance setting method
一片葉子兩三萬?植物消費爆火背後的“陽謀”
随机推荐
Lumion 11.0软件安装包下载及安装教程
遇到慢SQL该怎么办?(下)
Recent applet development records
微服务架构介绍
RC振荡器和晶体振荡器简介
[leetcode] day97 remove linked list elements
【论文阅读|深读】RolNE: Improving the Quality of Network Embedding with Structural Role Proximity
Correct use of BigDecimal
强化学习如何用于医学影像?埃默里大学最新《强化学习医学影像分析》综述,阐述最新RL医学影像分析概念、应用、挑战与未来方向
MySQL execution process and sequence
Livox激光雷达硬件时间同步---PPS方法
Unicode string converted to Chinese character decodeunicode utils (tool class II)
Blackfly S USB3工业相机:缓冲区处理
Schedulx v1.4.0 and SaaS versions are released, and you can experience the advanced functions of cost reduction and efficiency increase for free!
centos8安裝mysql報錯:The GPG keys listed for the “MySQL 8.0 Community Server“ repository are already ins
Shell script quickly counts the number of lines of project code
建议收藏!!Flutter状态管理插件哪家强?请看岛上码农的排行榜!
一片叶子两三万?植物消费爆火背后的“阳谋”
低代码平台中的数据连接方式(上)
Web开发小妙招:巧用ThreadLocal规避层层传值