服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - c# 如何实现一个简单的json解析器

c# 如何实现一个简单的json解析器

2022-09-27 14:11NewAI C#

这篇文章主要介绍了c# 如何实现一个简单的json解析器,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

一、JSON格式介绍

  • JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。相对于另一种数据交换格式 XML,JSON 有着很多优点。例如易读性更好,占用空间更少等。在 web 应用开发领域内,得益于 JavaScript 对 JSON 提供的良好支持,JSON 要比 XML 更受开发人员青睐。所以作为开发人员,如果有兴趣的话,还是应该深入了解一下 JSON 相关的知识。本着探究 JSON 原理的目的,我将会在这篇文章中详细向大家介绍一个简单的JSON解析器的解析流程和实现细节。由于 JSON 本身比较简单,解析起来也并不复杂。所以如果大家感兴趣的话,在看完本文后,不妨自己动手实现一个 JSON 解析器。好了,其他的话就不多说了,接下来让我们移步到重点章节吧。
  • 在线JOSN校验格式化工具 如果在解析字符串的时候,拿不准这个是不是正确的JOSN,你可以在这个上面测试一下,有利于对自己代码的测试

二、解析原理介绍

  • 解析对象{}

对象结构是{"Key":[值]}的格式,所以先解析到Key字符串,将Key解析出来,然后在解析到值,因为值有可能是【字符串、值类型、布尔类型、对象、数组、null】所以需要根据前缀得到类型,并调用相应的解析方法,循环解析到“}”对象结尾

  • 解析数组[]

对象的结构是[[值],[值]],因为值有可能是【字符串、值类型、布尔类型、对象、数组、null】所以需要根据前缀得到类型,并调用相应的解析方法,循环解析到]数组结尾

  • 解析字符串

循环解析,需要判断是否遇到转义符\如果遇到,当前字符的下一个字符将是作为普通字符存入结果,如果遇到非转义的 " 字符则退出字符串读取方法,并返回结果

  • 解析值类型

循环拉取[0-9]包括.符号,然后调用转换成double类型方法

  • 解析布尔类型

转判断是 true 还是 false

  • 解析null

转判断是否为 null

解析元素流程图

c# 如何实现一个简单的json解析器

解析方法列表

 

方法名 方法作用
AnalysisJson 解析JSON字符串为C#数据结构
AnalysisJsonObject 解析JSON字符串为对象结构
AnalysisJsonArray 解析JSON字符串为数组结构
ReadElement 读取出一个JSON结构
ReadJsonNumber 读取出一个值类型结构
ReadJsonNull 读取出一个null结构
ReadJsonFalse 读取出一个false结构
ReadJsonTrue 读取出一个true结构
ReadString 读取出一个字符串结构
ReadToNonBlankIndex 读取到非空白字符下标位置

 

例1 解析JSON

{"Name":"张三","Age":18}

1.解析第一个字符{发现是JSON对象结构,调用AnalysisJsonObject方法来解析JSON对象格式

2.解析对象的方法开始循环解析 Key-Value结构直到}对象尾部字符

  • 先解析Key结构调用 ReadString来进行解析出Key字符串从而得到Name这个值
  • 然后解析Value因为值可能是任意结构所以调用ReadElement来解析出一个JSON结构
  • 读取第一个字符得到"从而知道这个Value是一个字符串,调用方法ReadString来读取到这个Value的值张三
  • 读取下一个字符发现不是JSON对象的结尾字符}是,字符代表下面还存在一个Key-Value结构,继续读取
  • 先解析Key结构调用 ReadString来进行解析出Key字符串从而得到Age这个值
  • 然后解析Value因为值可能是任意结构所以调用ReadElement来解析出一个JSON结构
  • 读取第一个字符发现是1是数字,代表下面的这个结构是数值类型调用方法ReadJsonNumber来读取数值类型
  • 读取下一个字符发现是}是JSON对象的结尾字符,退出JSON对象解析,返回解析的JSON对象结构实例

例2 解析JSON

[{"科目":"语文","成绩":99}]

1.解析第一个字符[发现是JSON数组结构,调用方法AnalysisJsonArray方法来解析出JSON数组结构

解析循环解析JSON数据结构直到遇到]数组结构结尾字符

因为数组中每个元素都是可能是任意类型数据,所以调用ReadElement方法来解析值

读取值的第一个字符{发现是JSON对象类型调用AnalysisJsonObject方法解析JSON对象

先解析Key结构调用 ReadString来进行解析出Key字符串从而得到科目这个值

然后解析Value因为值可能是任意结构所以调用ReadElement来解析出一个JSON结构

读取第一个字符得到"从而知道这个Value是一个字符串,调用方法ReadString来读取到这个Value的值语文

读取下一个字符发现不是JSON对象的结尾字符}是,字符代表下面还存在一个Key-Value结构,继续读取

先解析Key结构调用 ReadString来进行解析出Key字符串从而得到成绩这个值

然后解析Value因为值可能是任意结构所以调用ReadElement来解析出一个JSON结构

读取第一个字符发现是9是数字,代表下面的这个结构是数值类型调用方法ReadJsonNumber来读取数值类型

读取下一个字符发现是}是JSON对象的结尾字符,退出JSON对象解析,返回解析的JSON对象结构实例

读取下一个字符发现是]JSON数组的结尾,退出解析JSON数组,返回解析的JSON数组结构实例

三、代码实现

?
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
/// <summary>
/// JSON解析类型
/// </summary>
public static class JsonConvert
{
  /// <summary>
  /// 解析JSON
  /// </summary>
  /// <param name="text">待解析的JSON字符串</param>
  /// <returns>解析完成的JSON结构对象</returns>
  public static JsonElement AnalysisJson(string text)
  {
    var index = 0;
    //读取到非空白字符
    ReadToNonBlankIndex(text, ref index);
    if (text[index++] == '[')
      //解析数组
      return AnalysisJsonArray(text, ref index);
    //解析对象
    return AnalysisJsonObject(text, ref index);
  }
 
  /// <summary>
  /// 解析JSON对象
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引位置</param>
  /// <returns>JSON对象</returns>
  private static JsonObject AnalysisJsonObject(string text, ref int index)
  {
    var jsonArray = new JsonObject();
    do
    {
      ReadToNonBlankIndex(text, ref index);
      if (text[index] != '"') throw new JsonAnalysisException($"不能识别的字符“{text[index]}”!应为“\"”",index);
      index++;
      //读取字符串
      var name = ReadString(text, ref index);
      ReadToNonBlankIndex(text, ref index);
      if (text[index] != ':') throw new JsonAnalysisException($"不能识别的字符“{text[index]}”!",index);
      index++;
      ReadToNonBlankIndex(text, ref index);
      if (jsonArray.ContainsKey(name)) throw new JsonAnalysisException($"已经添加键值:“{name}”",index);
      //读取下一个Element
      jsonArray.Add(name, ReadElement(text, ref index));
      //读取到非空白字符
      ReadToNonBlankIndex(text, ref index);
    } while (text[index++] != '}');
 
    return jsonArray;
  }
 
  /// <summary>
  /// 解析JSON数组
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引位置</param>
  /// <returns>JSON数组</returns>
  private static JsonArray AnalysisJsonArray(string text, ref int index)
  {
    var jsonArray = new JsonArray();
    do
    {
      ReadToNonBlankIndex(text, ref index);
      //读取下一个Element
      jsonArray.Add(ReadElement(text, ref index));
      //读取到非空白字符
      ReadToNonBlankIndex(text, ref index);
    } while (text[index++] != ']');
 
    return jsonArray;
  }
 
  /// <summary>
  /// 读取JSONElement
  /// </summary>
  /// <param name="text">字符串</param>
  /// <param name="index">开始下标</param>
  /// <returns>下一个Element</returns>
  private static JsonElement ReadElement(string text, ref int index)
  {
    switch (text[index++])
    {
      case '[':
        return AnalysisJsonArray(text, ref index);
      case '{':
        return AnalysisJsonObject(text, ref index);
      case '"':
        return new JsonString(ReadString(text, ref index));
      case 't':
        return ReadJsonTrue(text, ref index);
      case 'f':
        return ReadJsonFalse(text, ref index);
      case 'n':
        return ReadJsonNull(text, ref index);
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        return ReadJsonNumber(text, ref index);
      default:
        throw new JsonAnalysisException($"未知Element“{text[index]}”应该为【[、{{、\"、true、false、null】", index);
    }
  }
 
  /// <summary>
  /// 读取值类型
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引</param>
  /// <returns>JSON数值类型</returns>
  private static JsonNumber ReadJsonNumber(string text, ref int index)
  {
    var i = index;
    while (i < text.Length && char.IsNumber(text[i]) || text[i] == '.') i++;
    if (double.TryParse(text.Substring(index - 1, i - index + 1), out var value))
    {
      index = i;
      return new JsonNumber(value);
    }
 
    throw new JsonAnalysisException("不能识别的数字类型!", i);
  }
 
  /// <summary>
  /// 读取NULL
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引</param>
  /// <returns>读取NULL</returns>
  private static JsonNull ReadJsonNull(string text, ref int index)
  {
    if (text[index++] == 'u' &&
      text[index++] == 'l' &&
      text[index++] == 'l')
    {
      return new JsonNull();
    }
 
    throw new JsonAnalysisException("读取null出错!", index);
  }
 
  /// <summary>
  /// 读取FALSE
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引</param>
  /// <returns>布尔值-假</returns>
  private static JsonBoolean ReadJsonFalse(string text, ref int index)
  {
    if (text[index++] == 'a' &&
      text[index++] == 'l' &&
      text[index++] == 's' &&
      text[index++] == 'e')
    {
      return new JsonBoolean(false);
    }
 
    throw new JsonAnalysisException("读取布尔值出错!", index);
  }
 
  /// <summary>
  /// 读取TRUE
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引</param>
  /// <returns>布尔值-真</returns>
  private static JsonBoolean ReadJsonTrue(string text, ref int index)
  {
    if (text[index++] == 'r' &&
      text[index++] == 'u' &&
      text[index++] == 'e')
    {
      return new JsonBoolean(true);
    }
    throw new JsonAnalysisException("读取布尔值出错!",index);
  }
 
  /// <summary>
  /// 读取字符串
  /// </summary>
  /// <param name="text">JSON字符串</param>
  /// <param name="index">开始索引</param>
  /// <returns>字符串值</returns>
  private static string ReadString(string text, ref int index)
  {
    //是否处于转义状态
    var value = new StringBuilder();
    while (index < text.Length)
    {
      var c = text[index++];
      if (c == '\\')
      {
        value.Append('\\');
        if (index >= text.Length)
          throw new JsonAnalysisException("未知的结尾!",index);
        c = text[index++];
        value.Append(c);
        if (c == 'u')
        {
          for (int i = 0; i < 4; i++)
          {
            c = text[index++];
            if (IsHex(c))
            {
              value.Append(c);
            }
            else
            {
              throw new JsonAnalysisException("不是有效的Unicode字符!",index);
            }
          }
        }
      }
      else if (c == '"')
      {
        break;
      }
      else if (c == '\r' || c == '\n')
      {
        throw new JsonAnalysisException("传入的JSON字符串内容中不允许有换行!",index);
      }
      else
      {
        value.Append(c);
      }
    }
 
    return value.ToString();
  }
 
  /// <summary>
  /// 判断是否为16进制字符
  /// </summary>
  private static bool IsHex(char c)
  {
    return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
  }
 
  /// <summary>
  /// 读取到非空白字符
  /// </summary>
  /// <param name="text">字符串</param>
  /// <param name="index">开始下标</param>
  /// <returns>非空白字符下标</returns>
  private static void ReadToNonBlankIndex(string text, ref int index)
  {
    while (index < text.Length && char.IsWhiteSpace(text[index])) index++;
  }
}

完整DEMO代码下载

Github项目地址(会持续更新):DEMO代码

以上就是c# 如何实现一个简单的json解析器的详细内容,更多关于c# 实现json解析器的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/liuzhenliang/archive/2020/07/20/AnalysisJson.html

延伸 · 阅读

精彩推荐
  • C#C#利用Label标签控件模拟窗体标题的移动及窗体颜色不断变换效果

    C#利用Label标签控件模拟窗体标题的移动及窗体颜色不断变换效果

    Label标签控件相信对大家来说都不陌生,下面这篇文章主要给大家介绍了关于C#利用Label标签控件模拟窗体标题的移动及窗体颜色不断变换效果的相关资料,...

    cnc11532022-02-16
  • C#C#配置文件操作类分享

    C#配置文件操作类分享

    这篇文章主要分享了C#配置文件操作类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    孤者自清6752022-01-11
  • C#Unity3D基于UGUI实现虚拟摇杆

    Unity3D基于UGUI实现虚拟摇杆

    这篇文章主要为大家详细介绍了Unity3D基于UGUI实现虚拟摇杆,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    一缕残阳10492022-08-31
  • C#C#模拟http 发送post或get请求的简单实例

    C#模拟http 发送post或get请求的简单实例

    下面小编就为大家带来一篇C#模拟http 发送post或get请求的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C#教程网3702021-11-24
  • C#Unity shader实现百叶窗特效

    Unity shader实现百叶窗特效

    这篇文章主要为大家详细介绍了Unity shader实现百叶窗特效,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    张宇成10102022-08-10
  • C#C#利用时间和随即字符串创建唯一的订单编号

    C#利用时间和随即字符串创建唯一的订单编号

    本文介绍了利用时间和随机字符串组合生成唯一订单号的示例,从而保证订单号不会重复,希望能够对大家有所帮助。...

    Darren Ji4062021-11-17
  • C#关于nancy中的身份验证

    关于nancy中的身份验证

    在nancy中,身份验证分为basic ,form ,token,stateless几种,basic和form这里不说了,本文重点介绍token验证,需要的朋友一起看看吧...

    99re7522021-10-26
  • C#C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串的方法

    C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符

    本文主要介绍了C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串的方法:利用反射,读取一个类型的所有属性,然后再把属性转换成XM...

    弎吩锺熱℃6782021-12-14