ToTxt 序列化方法

下载地址:https://pan.baidu.com/s/1sKnnDNKr2tyNd0NIpXsagA 提取码:9e76
测试工程:https://pan.baidu.com/s/1Dk68RQe1ZMIarjgHmjG0VQ 提取码:n22s

ToTxt 是一种将C# 对象转为txt的一种序列化方法。
ToTxt 可以以下字段的转换:
需要序列化的C#对象,必须实现:[TXTClass]属性,且需要实现序列化的字段必须实现[TXTField]属性且访问权限为public
这个两个属性表明,该对象或字段需要序列化。
[TXTField]属性有一个Alias字段,该字段可以为需要序列化的字段提供一个别名,别名可以防止代码混淆后,无法实现反序列化的问题。如果未指定别名,将会使用字段的名称。

ToTxt 支持大部分的数据格式以及数据结构:

1.Enum 类型
2.基元类型(float,int,bool,double 等)
3.字符串(string)
4.结构(struct)
5.类(class)
6.数组
7.List
8.Dictionary

复杂List:
List<List<string>> |List<string[]> |List<Dictionary<string,int>>等
以及复杂的Dictionary:
Dictionary<string,string>|Dictionary<string,string[]>|Dictionary<string,List<int>>|Dictionary<string,Dictionary<string,int>>等

**不支持多维数组**

ToTxt 中分为两部分:
1.ToTxt ,这个类为静态类,主要实现对C#对象序列化和反序列化的实现

方法描述
string Serialization(object target)序列化目标对象
SeriElement(object item)序列化任意目标对象
T Deserialization(string value)反序列化
object DeseriElement(string value,Type fieldType)反序列化任何目标
TXTParser TXTParse(string value)获取TXT解析器

例如:


		[TXTClass]
		public class CObject
		{
			[TXTField("ObjectName")] public string Name;
			[TXTField] public int Level;
		}

		CObject o = new CObject ();
		o.Name = "Unity";
		o.Level = 10;
		string value = ToTxt.Serialization (o);

		CObject t = ToTxt.Deserialization<CObject> (value);
		Debug.Log (t.Name);
		Debug.Log (t.Level);

2.TXTParser txt解析器,可以手动对所需字段进行序列化或反序列化:

方法描述
void Add(string key,object value)添加字段
string Serialization()序列化
void Deserialization(string value)反序列化
string this[string key]根据key获取对应的序列txt
bool ContainsKey(string key)判断是否包含这个key
T Convert(string value)将序列txt 转为对象

例如:

		TXTParser parser = new TXTParser ();
		parser.Add ("ID", 20);
		parser.Add ("Name", "Unity");
		string value = parser.Serialization ();
		TXTParser t = new TXTParser ();
		t.Deserialization (value);
		int id = t.Convert<int> (t ["ID"]);
		string name = t ["Name"];
		Debug.Log (id);
		Debug.Log (name);

序列化后的文本格式:
例如,有以下代码:

///Object 类型
public enum CObjectType
{
	Enemy,
	Player
}

///Object 配置
[TXTClass]
public struct CObjectConfig
{
	[TXTField] public float Speed;
	[TXTField] public int AssetID;

}
///Object 属性
[TXTClass]
public class CObjectAttribute
{
	[TXTField] public int Hp;
	[TXTField] public int MapHp;

	public int Mp = 0;

}
///Ojbect
[TXTClass]
public class CObject
{
	[TXTField("ObjectName")] public string Name;
	[TXTField] public int Level;
	[TXTField] public CObjectType CObjectType;

	[TXTField] public CObjectConfig Config;
	[TXTField] public CObjectAttribute Attribute;

}
public class MonoTEST : MonoBehaviour {

	// Use this for initialization
	void Start () {
		//创建一个CObject
		CObject o = new CObject ();
		o.Name = "Unity";
		o.Level = 10;
		o.CObjectType = CObjectType.Enemy;
		o.Config.Speed = 5;
		o.Config.AssetID = 10;
		o.Attribute = new CObjectAttribute ();
		o.Attribute.Hp = 80;
		o.Attribute.MapHp = 100;
		//序列化
		string value = ToTxt.Serialization (o);
		Debug.Log (value);
	}
}

会得到以下文本:

{
	ObjectName=Unity
	Level=10
	CObjectType=Enemy
	Config="c_0"
	Attribute="c_1"
}

"c_0"={
	Speed=5
	AssetID=10
}

"c_1"={
	Hp=80
	MapHp=100
}

模块:每一对大括号包围的内容为一个模块
第一模块,就是对象的主模块,包含序列化对象中定义的且实现[TXTField]以及访问级别为public的字段名称(或别名)及内容。
因为在CObject中Name使用了别名 ObjectName,所以此处使用ObjectName作为字段名存储。
Config与Attribute 都为新的结构体(struct,class),所以会额外创建两个模块("c_0""c_1"),来保存这个两个结构内容,使用"c_num"方式的模块名进行关联(num为除主模块外其他模块的数量)。
在Attribute中因为字段Mp没有使用[TXTField]属性所以在模块"c_1"中没有此字段值。

注意:"c_num" 两侧的双引号代表着这是个新的模块,所以不能舍弃。所以在字符串变量赋值时,应避免使用双引号开始以及结尾,

数组、列表、字典:
例如:

		TXTParser parser = new TXTParser ();
		parser.Add ("IntAry", new int[]{ 1, 2, 3 });
		parser.Add ("IntList", new List<int> (){ 4, 5, 6 });
		parser.Add ("CObjectList", new List<CObject> (){ new CObject (), new CObject () });
		parser.Add ("StringIntDic", new Dictionary<string,int> (){ { "a",1 }, { "b",2 } });
		Debug.Log (parser.Serialization ());

得到以下序列文本:

{
	IntAry=[1,2,3]
	IntList=[4,5,6]
	CObjectList=["c_1","c_3"]
	StringIntDic=[a=1,b=2]
}

"c_0"={
	Speed=0
	AssetID=0
}

"c_1"={
	ObjectName=null
	Level=0
	CObjectType=Enemy
	Config="c_0"
	Attribute=null
}

"c_2"={
	Speed=0
	AssetID=0
}

"c_3"={
	ObjectName=null
	Level=0
	CObjectType=Enemy
	Config="c_2"
	Attribute=null
}

通过文本,我们看到数组与列表的序列化后得到文本基本上是一样的。如果数组或列表为结构或类,都会根据对应的元素生产新的模块,而列表中存储的是模块名称。
因为新创建的CObject对象,我们没有对NameAttribute赋值,又因为这两种类型都为引用模式,所以存储的为null值。
字典生成的序列文本中,使用=将key和value进行关联。

反序列化时,会先将整个序列文本,切割成一个个模块,然后对主模块(默认键为 “main”)进行解析,并与反序列对象中的字段进行匹配,然后根据字段的 类型,将文本转为对应类型。如果,字段是struct或class,会找打对应的模块,然后对该模块进行解析。

在使用过程中,应尽量避免自身引用以及父类引用,否则可能会造成死循环

线阶段就这么多的功能,后续可能还会加上加密功能等。

下面为我写的测试代码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public enum StateType
{
	None,
}

[TXTClass]
public class Test1{
	[TXTField] public int Int;
	[TXTField] public string String;
	[TXTField] public Test2 test2;
	[TXTField] public Test3 test3 = new Test3();
}

[TXTClass]
public class Test3{
	[TXTField] public float Float;
}

[TXTClass]
public struct Test2{

	[TXTField] public int Int;
	[TXTField] public float Float;
}

[TXTClass]
public class Test  {


	[TXTField] public string Name = "text";
	[TXTField("222")] public int Int = 0;
	[TXTField] public float Float = 0;
	[TXTField] public bool Bool = false;
	[TXTField] public double Double = 0;

	[TXTField] public Test1 t1 = new Test1();
	[TXTField] public Test1 t3;
	[TXTField] public Test2 t2;

	[TXTField("haha")] public int[] IntAry = new int[]{1,2,3};
	[TXTField] public int[] IntAry1;
	[TXTField] public float[] FloatAry = new float[]{1.0f,2.0f,3.0f};
	[TXTField] public bool[] BoolAry = new bool[]{false,false,true};
	[TXTField] public string[] StringAry = new string[]{"a","b","c"};
	[TXTField] public List<int> IntList = new List<int>(){1,2,3};
	[TXTField] public Test2[] Test2Ary = new Test2[2];
	[TXTField] public Test1[] Test1Ary = new Test1[]{new Test1(){},new Test1(){}};
	[TXTField] public StateType StateType = StateType.None;
	[TXTField] public List<Test1> Test1List = new List<Test1> (){ new Test1 (), new Test1 () };
	[TXTField] public List<int[]> IntAryList = new List<int[]>(){new int[]{1,2,3}};
	[TXTField] public List<List<string>> StringListList = new List<List<string>>(){new List<string>(){"a","b","c"}};
	[TXTField] public List<List<Test1>> ClassListList = new List<List<Test1>> (){ new List<Test1> () {
			new Test1 (),
			new Test1 ()
		} };
	[TXTField] public Dictionary<string,string> Dic = new Dictionary<string, string>(){{"a","bbbb"},{"b","ccccc"}};
	[TXTField] public Dictionary<string,string[]> DicAry = new Dictionary<string, string[]> () {
		 {
			"a",
			new string[]{ "aa", "bb" }
		},
		 {
			"b",
			new string[] {
				"bb",
				"cc"
			}
		}
	};
	[TXTField] public Dictionary<string,int> DicInt = new Dictionary<string, int> (){ { "a",0 }, { "b",1 },{"c",1}};
	[TXTField] public Dictionary<string,List<Test1>> DicTest1 = new Dictionary<string, List<Test1>> (){ {
			"a",
			new List<Test1> (){ new Test1 () }
		},{"b",new List<Test1>(){new Test1(),new Test1()}} };
	[TXTField] public Dictionary<string,Dictionary<string,int>> DicDic = new Dictionary<string,Dictionary<string,int>> () {
		{ "a",new Dictionary<string,int> (){ { "b",1 } } }
	};
	[TXTField] public List<Dictionary<string,int>> ListDic = new List<Dictionary<string, int>> () {
		new Dictionary<string, int> (){ { "a",1 } }

	};

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;

public enum CObjectType
{
	Enemy,
	Player
}

[TXTClass]
public struct CObjectConfig
{
	[TXTField] public float Speed;
	[TXTField] public int AssetID;

}

[TXTClass]
public class CObjectAttribute
{
	[TXTField] public int Hp;
	[TXTField] public int MapHp;

	public int Mp = 0;

}

[TXTClass]
public class CObject
{
	[TXTField("ObjectName")] public string Name;
	[TXTField] public int Level;
	[TXTField] public CObjectType CObjectType;

	[TXTField] public CObjectConfig Config;
	[TXTField] public CObjectAttribute Attribute;

}

public class MonoTEST : MonoBehaviour {

	// Use this for initialization
	void Start () {

		/*
		CObject o = new CObject ();
		o.Name = "Unity";
		o.Level = 10;
		o.CObjectType = CObjectType.Enemy;
		o.Config.Speed = 5;
		o.Config.AssetID = 10;
		o.Attribute = new CObjectAttribute ();
		o.Attribute.Hp = 80;
		o.Attribute.MapHp = 100;

		string value = ToTxt.Serialization (o);
		Debug.Log (value);
		CObject t = ToTxt.Deserialization<CObject> (value);
		Debug.Log (t.Name);
		Debug.Log (t.Level);
*/
		/*
		Test test = new Test ();
		test.Int = 10;
		test.Double = 20;
		test.IntAry = new int[]{ 7, 89, 5 };
		test.Test1List.Add (new Test1 (){ Int = 5 });
		test.Test1List.Add (new Test1 (){ String = "哈哈" });
		test.DicTest1 ["a"] [0].Int = 30;
		string value = ToTxt.Serialization (test);
		Debug.Log(value);
		Test test1 = ToTxt.Deserialization<Test> (value);
		foreach (var data in test1.DicTest1) {
			for (int i = 0; i < data.Value.Count; i++)
				Debug.Log (data.Key + "=>" + data.Value [i].Int);
		}
		/*
		for (int i = 0; i < test1.Test1List.Count; i++)
			Debug.Log (test1.Test1List [i].Int);
		Test test3 = new Test ();
		TXTParse test2 = ToTxt.TXTParse (value);
		test3.Int = test2.Convert<int> (test2 ["Int"]);
*/
		/*
		TXTParser parser = new TXTParser ();
		parser.Add ("ID", 20);
		parser.Add ("Name", "Unity");
		string value = parser.Serialization ();
		TXTParser t = new TXTParser ();
		t.Deserialization (value);
		int id = t.Convert<int> (t ["ID"]);
		string name = t ["Name"];
		Debug.Log (id);
		Debug.Log (name);

		Debug.Log (value);
		string aaa = "None";
		*/
		//object value = Convert.ChangeType (test, typeof(int));
		//Debug.Log ((int)value);
		//value = Convert.ChangeType(test,typeof(float));
		//Debug.Log ((float)value);
		//object value = Convert.ChangeType(test,typeof(bool));
		//Debug.Log ((bool)value);
		//object value = Enum.Parse(typeof(StateType),test);
		//Debug.Log ((StateType)value);

		TXTParser parser = new TXTParser ();
		parser.Add ("IntAry", new int[]{ 1, 2, 3 });
		parser.Add ("IntList", new List<int> (){ 4, 5, 6 });
		parser.Add ("CObjectList", new List<CObject> (){ new CObject (), new CObject () });
		parser.Add ("StringIntDic", new Dictionary<string,int> (){ { "a",1 }, { "b",2 } });

		Debug.Log (parser.Serialization ());

		/*
		Debug.Log ("IntAry: " + parser ["IntAry"]);
		Debug.Log ("IntList:" + parser ["IntList"]);
		Debug.Log ("CObjectList:" + parser ["CObjectList"]);
		Debug.Log ("StringIntDic" + parser ["StringIntDic"]);
		*/
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
用python根据需求完成一个TXT解析器的简单开发 一 修改说明: 需求一: 一开始说要解析UECapabilityInfo 消息里的supportedBandCombination-r10 这个IE里的CA组合转化成易阅读的表现形式. 我以为一组CA组合就是一组: bandEUTRA-r10 ca-BandwidthClassUL-r10 ca-BandwidthClassDL-r10 supportedMIMO-CapabilityDL-r10 功能实现: 有效信息筛选:于是就用循环把UECapabilityInformation的数据里每一行作为一个元素放到list里面 然后用bandEUTRA-r10作为一组CA的识别信息、在筛选出同组ca-BandwidthClassUL-r10、ca-BandwidthClassDL-r10、supportedMIMO-CapabilityDL-r10的信息,添加保存到字符串中,然后再把字符串作为元素添加到list中去。最后遍历list的元素写入目标文件 需求二: 然后收到反馈CA组合的理解是错误的。一组CA组合应该是以大括号作为识别的,里面可能包含多组: bandEUTRA-r10: ca-BandwidthClassUL-r10 ca-BandwidthClassDL-r10 supportedMIMO-CapabilityDL-r10 CA组合识别原理:在查看UECapabilityInformation内的CA组合后 发现CA组合内第一个 bandEUTRA-r10因为比其他bandEUTRA-r10多了一层的CA组合的大括号,所以如果给每一行增加索引的话就会发现除了第一个bandEUTRA-r10,其他bandEUTRA-r10到上一个supportedMIMO-CapabilityDL-r10的距离都是一样的,为了减少复杂度,我删除了所有’{’,这样所有除了所有CA组合第一个bandEUTRA-r10往上第四行是’}’其他bandEUTRA-r10的往上第四行都是supportedMIMO-CapabilityDL-r10 功能实现: 添加索引:便利时用了for enumerate()循环,这样便利时可以在循环时,自动为每个元素生成索引 CA组合识别:在识别到bandEUTRA-r10时,增加一个判断if datalist1[index-4].startswith(),如果bandEUTRA-r10的往上第四行是supportedMIMO-CapabilityDL-r10说明同组CA未结束,把筛选的有效信息强制类型转换后添加在上个元素末尾,反之则说明是个新的CA组合,往列表里添加一个新的元素。 需求三: 之后收到反馈CA组合虽然识别了,但是排序不行,需要按照CA组合支持的band进行排序 功能实现: 排序:于是我在识别完CA组合后,增加了一个循环和count(),用CA组合里的’-’给它们归类 比如1AA,11A,21AA是一类;1A-1A,2A-1AA,3A-1A是一类 在用一个中间变量保存开头的band的数字,一个类中把开头支持band的数字字母相同的CA组合归为一行 比如1A-21A,1A-22A一类1AA-2AA 1AA-3AA为一类 需求四: 之后收到反馈,CA组合分类不能只按照开头比较分类,不然一但数据多了会对查阅带来极大不便,应该按照每组CA组合中bandEUTRA-r10的值进行判断,比如1AA-2AA,1A-2AA和1AA-2A应该归在同一行 实现原理:首先我想的是按位比较数字,但是因为字母的数量不稳定,数字的位置不一定对应,然后我就想把数字全部提取出来作为索引,在相应的索引后面添加同组元素,用dict来实现排序。难点就在于从字符串中提取数字。后来在python的正则表达式中找到相关的处理函数compile()(设置匹配对象类型)和findall()(找到所有匹配对象并以list返回)。 功能实现: 第二次排序:在上次的排序中我保留了分类和从小到大的排序。方便提取索引时,索引也是从小到大。每遍历一个元素(CA组合有效信息),就compile()和findall(),从该元素中提取数字组合(在compile()的参数中添加()就能够使提取的内容成为一组数据),然后通过dict自带函数setdefault()添加索引,并可以设置索引值为list类型(dict类型的索引的值不可变,但如果类型为list,list的内容可以进行改动),避免重复索引,在本次遍历中完成将元素添加到索引值对应的list中去 需求五: 之后对程序进行测试,在测试test2时发现layers增加了fourlayers类型后,用来代表layers的数字2和4会影响分类结果。比如1AA(2)-1AA(2)和1A(4)-1A(2)会被归为两类。 test1:当CA组合的格式为xx-xx-xx-xx-xx(最长可识别为五位元素的组合,再长就需要修改代码) test2:当CA组合包含fourLayers test3:当CA组合缺失某种格式比如xx-xx时发现layers增加了fourlayers 功能实现: : 解除layers对排序的影响:用II 和 IV替代2,4来表示layers,测试后不影响阅读与分类 二、整体程序架构: 1.通过循环和自带的startswith()先将每组CA组合的有效信息识别 2.通过sorted()函数将所有CA组合从小到大排列 3.通过count()函数将所有CA组合根据格式不同分类 4.通过循环和正则表达式的split()对所有CAlist数据进行处理(用split处理只是防止出现不必要的错误) 5.通过循环和正则表达式compile()和findall()识别所有CA组合中数字,并将同一组合中的数字合为一个元素(在同一循环,用这个数字的元素作为一个dict的索引),用dict自带的setdefault()进行Key的添加顺便设置Key的值为list,避免Key重复,在用append把当前Key的字符串,添加到Key对应值的list中去 6.最后对dict整体遍历,将每一个Key的值输出到文本中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建宁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值