开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1811

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 1291|回复: 118

[jskymoon] 自动生成可序列化的Json解析类【工具+源码】

  [复制链接]  [移动端链接]
排名
6585
昨日变化
60

7

主题

106

帖子

1022

积分

Rank: 9Rank: 9Rank: 9

UID
85548
好友
4
蛮牛币
988
威望
0
注册时间
2015-3-27
在线时间
595 小时
最后登录
2017-8-17

专栏作家活力之星

发表于 2017-7-27 16:19:51 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 jskymoon 于 2017-7-27 16:31 编辑

前言
很多项目喜欢使用Json或Xml配置数据,Unity从5.3推出了JsonUtility。
这样大多数情况就不用导入插件去解析Json了,可以使用它直接解析Json。如下面的Json:
[C#] 纯文本查看 复制代码
{
     "Name" : "Yumo",
     "Level" : 7,
     "Stats" : [ 4,7 ]
}


你可以先声明一个对应的解析类:
[C#] 纯文本查看 复制代码
[System.Serializable]
public class Creature
{
    public string Name;
    public int Level;
    public int[] stats;
}

然后,直接调用解析方法即可:
[C#] 纯文本查看 复制代码
Creature Yumo = JsonUtility.FromJson<Creature>(jsonString);




很方便啊~但是如果我要解析的是下面的Json呢
[C#] 纯文本查看 复制代码
{
    "glossary": {
        "title": "example glossary",
                "GlossDiv": {
            "title": "S",
                        "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
                                        "SortAs": "SGML",
                                        "GlossTerm": "Standard Generalized Markup Language",
                                        "Acronym": "SGML",
                                        "Abbrev": "ISO 8879:1986",
                                        "GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
                                                "GlossSeeAlso": ["GML", "XML"]
                    },
                                        "GlossSee": "markup"
                }
            }
        }
    }
}




当然,你可以一层层的去对应写解析类,但是这样会比较浪费时间。而且当Json结构发生变化时你需要再去调整。


需求
因此我们接下来做的就是自动生成Json解析类,效果如下图:







分析
既然要自动生成Json解析类,那么需要先了解Json。
Json大致分为五种类型:object、array、string、number、bool


object 的结构如下:


array 的结构如下:


由上面的结构图可以发现,Json对象其实就是一个键值对的集合。因此一个最基本的思路就是:
先将Json解析成C#字典类型,即Dictionary<string, object>。然后根据此字典类型生成对应的C#解析类

那么如何取出Json中所有的键值对呢?
刚开始打算直接用一个正则就能取出Json里所有数据的,后来Google了下发现.Net不支持递归正则
因此,我们将采用C#递归+正则的方式取出数据。

代码流程
1.定义需要用到的正则,代码如下:
[C#] 纯文本查看 复制代码
#region 正则表达式
//解析键值对
private const string regexPairOf = @"\s*" + regexString + @"\s*:\s*";//\s*"([^"]*)"\s*:\s*

private const string regexPairOfObject = regexPairOf + regexObject;
private const string regexPairOfArray = regexPairOf + regexArray;
private const string regexPairOfString = regexPairOf + regexString;
private const string regexPairOfNumber = regexPairOf + regexNumber;
private const string regexPairOfBool = regexPairOf + regexBool;

//对象
private const string regexObject = @"(?<!\[[\s\S]*)\{((?>\{(?<c>)|[^\{\}]+|\}(?<-c>))*(?(c)(?!)))\}";//前面不含[的{}

//数组
private const string regexArray = @"\[((?>\[(?<c>)|[^\[\]]+|\](?<-c>))*(?(c)(?!)))\]";

//基础类型
private const string regexString = "\"([^\"]*)\"";//"[^"]*"
private const string regexNumber = @"(-?(?=[1-9]|0(?!\d))\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)";
private const string regexBool = "(true|false|null)";
#endregion


2.将json传入函数ParseRoot()
[C#] 纯文本查看 复制代码
private static Dictionary<string, object> ParseRoot(string json)
{
    Match match = Regex.Match(json, regexObject);
    if (match.Success)
    {
        string content = match.Groups[1].Value;
        return ParseObject(ref content);
    }
    return null;
}


3.使用ParseObject() 解析并返回一个ObjectDictionary
[C#] 纯文本查看 复制代码
private static Dictionary<string, object> ParseObject(ref string content)
{
    //解析members
    Pair[] members = ParseMembers(ref content);

    //创建Object
    Dictionary<string, object> result = new Dictionary<string, object>();
    if (members != null)
    {
        for (int i = 0, l = members.Length; i < l; i++)
        {
            result.Add(members[i].key, members.value);
        }
    }
    return result;
}


4.解析对象中的键值对将其封装成数组
[C#] 纯文本查看 复制代码
private static Pair[] ParseMembers(ref string content)
{
    List<Pair> membersList = new List<Pair>();

    string original = content.ToString();

    //判断Object类型
    Pair[] pairsOfObject = ParsePairs(ref content, regexPairOfObject);
    foreach (Pair pair in pairsOfObject)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ParseObject(ref pair.content);
    }
    membersList.AddRange(pairsOfObject);

    //判断Array类型
    Pair[] pairsOfArray = ParsePairs(ref content, regexPairOfArray);
    foreach (Pair pair in pairsOfArray)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ParseArray(ref pair.content);
    }
    membersList.AddRange(pairsOfArray);

    //判断String类型
    Pair[] pairsOfString = ParsePairs(ref content, regexPairOfString);
    foreach (Pair pair in pairsOfString)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = pair.content;
    }
    membersList.AddRange(pairsOfString);

    //判断Number类型
    Pair[] pairsOfNumber = ParsePairs(ref content, regexPairOfNumber);
    foreach (Pair pair in pairsOfNumber)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ConfigTools.ConvertNumber(pair.content);
    }
    membersList.AddRange(pairsOfNumber);

    //判断Bool类型
    Pair[] pairsOfBool = ParsePairs(ref content, regexPairOfBool);
    foreach (Pair pair in pairsOfBool)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ConfigTools.ConvertBool(pair.content);
    }
    membersList.AddRange(pairsOfBool);

    //排序
    membersList.Sort(Pair.Compare);

    return membersList.ToArray();
}


5.将键值对中的数组类型解析成object[]
[C#] 纯文本查看 复制代码
private static object[] ParseArray(ref string content)
{
    List<object> array = new List<object>();

    //排序
    string original = content.ToString();
    List<Sort> sorts = new List<Sort>();

    //Object
    MatchCollection matchObjects = MatchesAndRemove(ref content, regexObject);
    foreach (Match match in matchObjects)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s),ParseObject(ref s)));
    }

    //数组
    MatchCollection matchArraies = MatchesAndRemove(ref content, regexArray);
    foreach (Match match in matchArraies)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), ParseArray(ref s)));
    }

    //String
    MatchCollection matchStrings = MatchesAndRemove(ref content, regexString);
    foreach (Match match in matchStrings)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), s));
    }

    //Number
    MatchCollection matchNumbers = MatchesAndRemove(ref content, regexNumber);
    foreach (Match match in matchNumbers)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), ConfigTools.ConvertNumber(s)));
    }

    //Bool
    MatchCollection matchBools = MatchesAndRemove(ref content, regexBool);
    foreach (Match match in matchBools)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), ConfigTools.ConvertBool(s)));
    }

    //进行排序
    sorts.Sort(Sort.Compare);
    foreach (Sort s in sorts)
    {
        array.Add(s.data);
    }

    return array.ToArray();
}


整个过程如下图:
p5.png

此流程不断递归,直至所有对象和数组中没有子对象或子数组


工具源码免费下载


p6.png
游客,如果您要查看本帖隐藏内容请回复







本帖被以下淘专辑推荐:


回复

使用道具 举报

4四处流浪
498/500
排名
5014
昨日变化
1

13

主题

111

帖子

498

积分

Rank: 4

UID
148479
好友
1
蛮牛币
671
威望
0
注册时间
2016-5-13
在线时间
168 小时
最后登录
2017-8-16
发表于 2017-7-27 17:50:01 | 显示全部楼层
这个好。。。。。。

回复

使用道具 举报

7日久生情
4996/5000
排名
251
昨日变化

0

主题

2313

帖子

4996

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
3215
好友
0
蛮牛币
290
威望
0
注册时间
2013-9-4
在线时间
1173 小时
最后登录
2017-8-17
发表于 2017-7-27 17:55:55 | 显示全部楼层
顶顶顶顶顶顶顶顶顶顶顶顶顶顶

回复 支持 反对

使用道具 举报

7日久生情
3983/5000
排名
50
昨日变化

0

主题

265

帖子

3983

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
14133
好友
0
蛮牛币
5062
威望
0
注册时间
2014-2-12
在线时间
1524 小时
最后登录
2017-8-17
发表于 2017-7-27 17:59:38 | 显示全部楼层
看看,是个很好的资源。

回复 支持 反对

使用道具 举报

排名
6585
昨日变化
60

7

主题

106

帖子

1022

积分

Rank: 9Rank: 9Rank: 9

UID
85548
好友
4
蛮牛币
988
威望
0
注册时间
2015-3-27
在线时间
595 小时
最后登录
2017-8-17

专栏作家活力之星

 楼主| 发表于 2017-7-27 18:16:11 | 显示全部楼层
这个工具是支持多种格式的,大家对这个工具有任何问题可以在本帖提出来~

回复 支持 反对

使用道具 举报

3偶尔光临
249/300
排名
7719
昨日变化
8

0

主题

72

帖子

249

积分

Rank: 3Rank: 3Rank: 3

UID
195174
好友
0
蛮牛币
359
威望
0
注册时间
2016-12-22
在线时间
65 小时
最后登录
2017-8-17
发表于 2017-7-27 19:35:02 | 显示全部楼层
支持支持 感谢楼主分享

回复 支持 反对

使用道具 举报

5熟悉之中
774/1000
排名
3268
昨日变化
21

12

主题

152

帖子

774

积分

Rank: 5Rank: 5

UID
172976
好友
4
蛮牛币
229
威望
0
注册时间
2016-9-30
在线时间
278 小时
最后登录
2017-8-17
发表于 2017-7-28 08:58:36 | 显示全部楼层
之前我也想过搞一个自动解析的,无奈水平有限就放弃了
么想到还真能开发出来,厉害了我的哥
好工具,感谢

回复 支持 反对

使用道具 举报

排名
6585
昨日变化
60

7

主题

106

帖子

1022

积分

Rank: 9Rank: 9Rank: 9

UID
85548
好友
4
蛮牛币
988
威望
0
注册时间
2015-3-27
在线时间
595 小时
最后登录
2017-8-17

专栏作家活力之星

 楼主| 发表于 2017-7-28 09:11:09 | 显示全部楼层
innaturegod 发表于 2017-7-28 08:58
之前我也想过搞一个自动解析的,无奈水平有限就放弃了
么想到还真能开发出来,厉害了我的哥
...

感谢支持~使用中有任何问题欢迎联系我~

回复 支持 反对

使用道具 举报

7日久生情
2597/5000
排名
439
昨日变化
2

3

主题

403

帖子

2597

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
100070
好友
1
蛮牛币
393
威望
0
注册时间
2015-5-13
在线时间
935 小时
最后登录
2017-8-17

活力之星

发表于 2017-7-28 09:15:17 | 显示全部楼层
感谢分享

回复

使用道具 举报

5熟悉之中
876/1000
排名
9505
昨日变化
121

4

主题

694

帖子

876

积分

Rank: 5Rank: 5

UID
209186
好友
0
蛮牛币
1458
威望
0
注册时间
2017-3-1
在线时间
100 小时
最后登录
2017-8-17
发表于 2017-7-28 09:18:09 | 显示全部楼层
谢谢分享,学习了

回复

使用道具 举报

6蛮牛粉丝
1162/1500
排名
1751
昨日变化
1

2

主题

220

帖子

1162

积分

Rank: 6Rank: 6Rank: 6

UID
65040
好友
1
蛮牛币
518
威望
0
注册时间
2015-1-1
在线时间
352 小时
最后登录
2017-8-15
发表于 2017-7-28 09:38:53 | 显示全部楼层
谢谢楼主分享!!!

回复

使用道具 举报

排名
30594
昨日变化
62

0

主题

1

帖子

11

积分

Rank: 1

UID
229908
好友
0
蛮牛币
41
威望
0
注册时间
2017-7-3
在线时间
6 小时
最后登录
2017-8-3
发表于 2017-7-28 09:56:22 | 显示全部楼层
这个有点厉害

回复

使用道具 举报

6蛮牛粉丝
1054/1500
排名
3801
昨日变化
18

6

主题

499

帖子

1054

积分

Rank: 6Rank: 6Rank: 6

UID
83438
好友
2
蛮牛币
1463
威望
0
注册时间
2015-3-23
在线时间
259 小时
最后登录
2017-8-17
发表于 2017-7-28 10:01:20 | 显示全部楼层
不错不错

回复

使用道具 举报

3偶尔光临
271/300
排名
7634
昨日变化
5

0

主题

103

帖子

271

积分

Rank: 3Rank: 3Rank: 3

UID
91378
好友
1
蛮牛币
294
威望
0
注册时间
2015-4-11
在线时间
56 小时
最后登录
2017-7-28
发表于 2017-7-28 10:01:47 | 显示全部楼层
谢谢楼主分享

回复

使用道具 举报

7日久生情
2672/5000
排名
226
昨日变化

11

主题

311

帖子

2672

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
52346
好友
0
蛮牛币
2686
威望
0
注册时间
2014-10-31
在线时间
686 小时
最后登录
2017-8-17
发表于 2017-7-28 10:02:49 | 显示全部楼层
感谢分享 感谢分享

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表