如何识别一个字符串是否Json格式
前言:
距离上一篇文章,又过去一个多月了,近些时间,工作依旧很忙碌,除了管理方面的事,代码方面主要折腾三个事:
1:开发框架(一整套基于配置型的开发体系框架)
2:CYQ.Data 数据层框架(持续的更新,最近也加入了Sybase的支持)
3:工作流流程图设计器。
由于这三个方面都涉及到Json,所以就谈谈这些天在Json上花下的心思。
关于造轮子:
很多人对于造轮子都会有自己的看法,这里提一下个人的观点:
个人认为:
1:首要是要具备造轮子的能力,然后再讨论造不造与浪不浪、轮子与时间的问题。
2:造轮子的、写文章的,永远比使用轮子的、看文章的,多经历了一些、多思考一些、多知道一些。
所以,别嫌造轮子折腾,虽然的确很折腾,不是有那么句:生命在于折腾,除了瞎折腾。
PS:本来文章是写Json常用的功能交互那块相关的知识,所以才有这一段。
不多扯了,扯多了都是蛋,还是回归正题吧。
如何识别一个字符串是不是Json。
网上搜了一下,找到两三个坑人的答案:
A:Js识别,Eval一下,成功就是,失败就挂。
B:C#识别,判断开始和结束符号:{}或[]
C:用正则表达式判断。
上面ABC答案都纯忽悠,只要认真一下,都不靠谱了。
经过我的研究,发现这是有很有挑战性的课题:
Json需要分析的情况,比想象的要多,举一个不太简单的Json:
[1,{"a":2},\r\n{"a":{}}, {"a":[]},{"a":[{}]},{"{[a":"\"2,:3,"a":33}]"}]
从上面这个Json中,就可以看出需要分析的有:
1:数组和Json数组。
2:键与值(无引号、双引号)的识别
3:无限级值嵌套(数组嵌套、Json嵌套)
4:7个关键符号[{,:"}]。
5:转义符号、空格、换行、回车处理。
回顾早些年写的JsonHelper
还记得CYQ.Data里JsonHelper的最初版本,仅处理了只有一级Json的简单情况,那时候分析Json就靠以下两种方法:
1:Split 分隔。
2:循环 indexOf 识别。
虽然偷工减料,投机取巧,但只要限定使用环境和条件、好在够用,也够简单。
当然了,现在情况变了,把限定的环境和条件去除后,事实上,要分析起来就没那么简单了。
故事一开始,思考了三天三夜
由于放开了条件,需要考虑无限级递归的,于是看似Split和IndexOf这种方式已经不奏效了。
字符串的分析方法看似需要改朝换代了,但我仍给Split和IndexOf寻求最后的机会。
经过层层思考与分析,发经没折了,只有祭出终极必杀招了。
终极大招:遍历字符,记录状态
一个万能的解决方法,就是遍历每个字符,然后记录这个字符前后左右上下东南西北中发白各种状态,再根据状态来识别下一个字符的动作。
1:首先有一个记录字符状态的类,如下图:
这个字符状态的记录类,我前后不断调整了N天,才终于感觉好像OK了。
2:接下来是字符的状态设置,根据不同的关键字,设置状态,如下图:
这是个漫长不断调试的过程,很折腾人。
3:一个可以不断递归Json的函数,如下图:
4:一个可以识别语法错误的函数:
5:最后是一个给外部的调用方法:
总结:
虽然本文是关于识别Json格式,实际上,它已经是Json解析类的核心,用它可以演化出Json的各种应用,有机会再介绍了。
事实上, 一开始是原打算写Json与Xml互转那一块的,写文的意原来自最近一周折腾工作流的流程设计器那一块:
从Xml出来到前端成为Json,编辑完后回去又要转回原始格式的Xml存档,所以在Xml和Json间,必须有一套协议,这些,大概是时间不够,所以临时变了一个题目。
关于Json的在线解析,以及Json和Xml和互转,临时我开了个域名 :tool.cyqdata.com,仅方便自己使用。
夜已深,该闭眼去梦里的世界旅游了。
最后是本文的源码:
![](/assets/blank.gif)
![](/assets/blank.gif)
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace CYQ.Data.Tool
6 {
7 /// <summary>
8 /// 分隔Json字符串为字典集合。
9 /// </summary>
10 internal class JsonSplit
11 {
12 private static bool IsJsonStart(ref string json)
13 {
14 if (!string.IsNullOrEmpty(json))
15 {
16 json = json.Trim('\r', '\n', ' ');
17 if (json.Length > 1)
18 {
19 char s = json[0];
20 char e = json[json.Length - 1];
21 return (s == '{' && e == '}') || (s == '[' && e == ']');
22 }
23 }
24 return false;
25 }
26 internal static bool IsJson(string json)
27 {
28 int errIndex;
29 return IsJson(json, out errIndex);
30 }
31 internal static bool IsJson(string json, out int errIndex)
32 {
33 errIndex = 0;
34 if (IsJsonStart(ref json))
35 {
36 CharState cs = new CharState();
37 char c;
38 for (int i = 0; i < json.Length; i++)
39 {
40 c = json[i];
41 if (SetCharState(c, ref cs) && cs.childrenStart)//设置关键符号状态。
42 {
43 string item = json.Substring(i);
44 int err;
45 int length = GetValueLength(item, true, out err);
46 cs.childrenStart = false;
47 if (err > 0)
48 {
49 errIndex = i + err;
50 return false;
51 }
52 i = i + length - 1;
53 }
54 if (cs.isError)
55 {
56 errIndex = i;
57 return false;
58 }
59 }
60
61 return !cs.arrayStart && !cs.jsonStart;
62 }
63 return false;
64 }
65
66 /// <summary>
67 /// 获取值的长度(当Json值嵌套以"{"或"["开头时)
68 /// </summary>
69 private static int GetValueLength(string json, bool breakOnErr, out int errIndex)
70 {
71 errIndex = 0;
72 int len = 0;
73 if (!string.IsNullOrEmpty(json))
74 {
75 CharState cs = new CharState();
76 char c;
77 for (int i = 0; i < json.Length; i++)
78 {
79 c = json[i];
80 if (!SetCharState(c, ref cs))//设置关键符号状态。
81 {
82 if (!cs.jsonStart && !cs.arrayStart)//json结束,又不是数组,则退出。
83 {
84 break;
85 }
86 }
87 else if (cs.childrenStart)//正常字符,值状态下。
88 {
89 int length = GetValueLength(json.Substring(i), breakOnErr, out errIndex);//递归子值,返回一个长度。。。
90 cs.childrenStart = false;
91 cs.valueStart = 0;
92 //cs.state = 0;
93 i = i + length - 1;
94 }
95 if (breakOnErr && cs.isError)
96 {
97 errIndex = i;
98 return i;
99 }
100 if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。
101 {
102 len = i + 1;//长度比索引+1
103 break;
104 }
105 }
106 }
107 return len;
108 }
109 /// <summary>
110 /// 字符状态
111 /// </summary>
112 private class CharState
113 {
114 internal bool jsonStart = false;//以 "{"开始了...
115 internal bool setDicValue = false;// 可以设置字典值了。
116 internal bool escapeChar = false;//以"\"转义符号开始了
117 /// <summary>
118 /// 数组开始【仅第一开头才算】,值嵌套的以【childrenStart】来标识。
119 /// </summary>
120 internal bool arrayStart = false;//以"[" 符号开始了
121 internal bool childrenStart = false;//子级嵌套开始了。
122 /// <summary>
123 /// 【0 初始状态,或 遇到“,”逗号】;【1 遇到“:”冒号】
124 /// </summary>
125 internal int state = 0;
126
127 /// <summary>
128 /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
129 /// </summary>
130 internal int keyStart = 0;
131 /// <summary>
132 /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
133 /// </summary>
134 internal int valueStart = 0;
135 internal bool isError = false;//是否语法错误。
136
137 internal void CheckIsError(char c)//只当成一级处理(因为GetLength会递归到每一个子项处理)
138 {
139 if (keyStart > 1 || valueStart > 1)
140 {
141 return;
142 }
143 //示例 ["aa",{"bbbb":123,"fff","ddd"}]
144 switch (c)
145 {
146 case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
147 isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。
148 break;
149 case '}':
150 isError = !jsonStart || (keyStart != 0 && state == 0);//重复结束错误 或者 提前结束{"aa"}。正常的有{}
151 break;
152 case '[':
153 isError = arrayStart && state == 0;//重复开始错误
154 break;
155 case ']':
156 isError = !arrayStart || jsonStart;//重复开始错误 或者 Json 未结束
157 break;
158 case '"':
159 case '\'':
160 isError = !(jsonStart || arrayStart); //json 或数组开始。
161 if (!isError)
162 {
163 //重复开始 [""",{"" "}]
164 isError = (state == 0 && keyStart == -1) || (state == 1 && valueStart == -1);
165 }
166 if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}]
167 {
168 isError = true;
169 }
170 break;
171 case ':':
172 isError = !jsonStart || state == 1;//重复出现。
173 break;
174 case ',':
175 isError = !(jsonStart || arrayStart); //json 或数组开始。
176 if (!isError)
177 {
178 if (jsonStart)
179 {
180 isError = state == 0 || (state == 1 && valueStart > 1);//重复出现。
181 }
182 else if (arrayStart)//["aa,] [,] [{},{}]
183 {
184 isError = keyStart == 0 && !setDicValue;
185 }
186 }
187 break;
188 case ' ':
189 case '\r':
190 case '\n'://[ "a",\r\n{} ]
191 case '\0':
192 case '\t':
193 break;
194 default: //值开头。。
195 isError = (!jsonStart && !arrayStart) || (state == 0 && keyStart == -1) || (valueStart == -1 && state == 1);//
196 break;
197 }
198 //if (isError)
199 //{
200
201 //}
202 }
203 }
204 /// <summary>
205 /// 设置字符状态(返回true则为关键词,返回false则当为普通字符处理)
206 /// </summary>
207 private static bool SetCharState(char c, ref CharState cs)
208 {
209 cs.CheckIsError(c);
210 switch (c)
211 {
212 case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
213 #region 大括号
214 if (cs.keyStart <= 0 && cs.valueStart <= 0)
215 {
216 cs.keyStart = 0;
217 cs.valueStart = 0;
218 if (cs.jsonStart && cs.state == 1)
219 {
220 cs.childrenStart = true;
221 }
222 else
223 {
224 cs.state = 0;
225 }
226 cs.jsonStart = true;//开始。
227 return true;
228 }
229 #endregion
230 break;
231 case '}':
232 #region 大括号结束
233 if (cs.keyStart <= 0 && cs.valueStart < 2 && cs.jsonStart)
234 {
235 cs.jsonStart = false;//正常结束。
236 cs.state = 0;
237 cs.keyStart = 0;
238 cs.valueStart = 0;
239 cs.setDicValue = true;
240 return true;
241 }
242 // cs.isError = !cs.jsonStart && cs.state == 0;
243 #endregion
244 break;
245 case '[':
246 #region 中括号开始
247 if (!cs.jsonStart)
248 {
249 cs.arrayStart = true;
250 return true;
251 }
252 else if (cs.jsonStart && cs.state == 1)
253 {
254 cs.childrenStart = true;
255 return true;
256 }
257 #endregion
258 break;
259 case ']':
260 #region 中括号结束
261 if (cs.arrayStart && !cs.jsonStart && cs.keyStart <= 2 && cs.valueStart <= 0)//[{},333]//这样结束。
262 {
263 cs.keyStart = 0;
264 cs.valueStart = 0;
265 cs.arrayStart = false;
266 return true;
267 }
268 #endregion
269 break;
270 case '"':
271 case '\'':
272 #region 引号
273 if (cs.jsonStart || cs.arrayStart)
274 {
275 if (cs.state == 0)//key阶段,有可能是数组["aa",{}]
276 {
277 if (cs.keyStart <= 0)
278 {
279 cs.keyStart = (c == '"' ? 3 : 2);
280 return true;
281 }
282 else if ((cs.keyStart == 2 && c == '\'') || (cs.keyStart == 3 && c == '"'))
283 {
284 if (!cs.escapeChar)
285 {
286 cs.keyStart = -1;
287 return true;
288 }
289 else
290 {
291 cs.escapeChar = false;
292 }
293 }
294 }
295 else if (cs.state == 1 && cs.jsonStart)//值阶段必须是Json开始了。
296 {
297 if (cs.valueStart <= 0)
298 {
299 cs.valueStart = (c == '"' ? 3 : 2);
300 return true;
301 }
302 else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"'))
303 {
304 if (!cs.escapeChar)
305 {
306 cs.valueStart = -1;
307 return true;
308 }
309 else
310 {
311 cs.escapeChar = false;
312 }
313 }
314
315 }
316 }
317 #endregion
318 break;
319 case ':':
320 #region 冒号
321 if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0)
322 {
323 if (cs.keyStart == 1)
324 {
325 cs.keyStart = -1;
326 }
327 cs.state = 1;
328 return true;
329 }
330 // cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1);
331 #endregion
332 break;
333 case ',':
334 #region 逗号 //["aa",{aa:12,}]
335
336 if (cs.jsonStart)
337 {
338 if (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1)
339 {
340 cs.state = 0;
341 cs.keyStart = 0;
342 cs.valueStart = 0;
343 //if (cs.valueStart == 1)
344 //{
345 // cs.valueStart = 0;
346 //}
347 cs.setDicValue = true;
348 return true;
349 }
350 }
351 else if (cs.arrayStart && cs.keyStart <= 2)
352 {
353 cs.keyStart = 0;
354 //if (cs.keyStart == 1)
355 //{
356 // cs.keyStart = -1;
357 //}
358 return true;
359 }
360 #endregion
361 break;
362 case ' ':
363 case '\r':
364 case '\n'://[ "a",\r\n{} ]
365 case '\0':
366 case '\t':
367 if (cs.keyStart <= 0 && cs.valueStart <= 0) //cs.jsonStart &&
368 {
369 return true;//跳过空格。
370 }
371 break;
372 default: //值开头。。
373 if (c == '\\') //转义符号
374 {
375 if (cs.escapeChar)
376 {
377 cs.escapeChar = false;
378 }
379 else
380 {
381 cs.escapeChar = true;
382 return true;
383 }
384 }
385 else
386 {
387 cs.escapeChar = false;
388 }
389 if (cs.jsonStart || cs.arrayStart) // Json 或数组开始了。
390 {
391 if (cs.keyStart <= 0 && cs.state == 0)
392 {
393 cs.keyStart = 1;//无引号的
394 }
395 else if (cs.valueStart <= 0 && cs.state == 1 && cs.jsonStart)//只有Json开始才有值。
396 {
397 cs.valueStart = 1;//无引号的
398 }
399 }
400 break;
401 }
402 return false;
403 }
404 }
405 }
![](/assets/blank.gif)
如何识别一个字符串是否Json格式相关推荐
- javascript中将字符串转换为json格式的三种方法
摘自:http://www.phpzixue.cn/detail1128.shtml javascript中将字符串转换为json格式的三种方法: json在我们js的开发过程中经常会用到像在使用a ...
- python str转json_Python中如何将一个字符串转换为json格式呢?
摘要: 下文讲述Python中字符串转换为json格式的方法分享,如下所示: json是各大语言都支持的一个对象,在web API开发中,我们经常使用json格式进行数据传输, 那么在Python中, ...
- php将字符串转换为json格式,js中将字符串转换为json格式的三种方法
json在js的开发过程中经常会用到,像在使用ajax开发的项目过程中,经常需要将json格式的字符串返回到前端,前端解析成json对象. 下面为大家介绍下将字符串转换为json对象的三种常用的方法: ...
- .NET字符串转JSON格式
原JSON字符串 {"errcode": 0, "errmsg": "ok", "process_instance": ...
- 一个java处理JSON格式数据的通用类(三)
/** *//** * 从json数组中解析出java Integer型对象数组 * @param jsonString * @return */ ...
- 一个java处理JSON格式数据的通用类(四)
public class DateJsonValueProcessor implements JsonValueProcessor ...{ public static final ...
- 一个java处理JSON格式数据的通用类(五)
本来上面转载的文章已经很全面了,不过还是再补充一下吧 /***************************************************************** * * @ ...
- java判断string字符串是不是json格式
public static boolean isJson(String content) { try { JSONObject.fromObject(conte ...
- 通过输入流获取的xml格式字符串转为json和map格式
通过输入流获取的xml格式字符串转为json和map格式 xml格式字符串转json格式代码: try {//通过输入流获取xml格式字符串数据ServletInputStream inputStre ...
- Python JSON格式与字符串转换(字符串转json、json转字符串)
1. 字符串转为JSON 源代码: import jsonstr = ''' [{"name": "Tom","gender": " ...
最新文章
- LOL手游上线!同步专属限量游戏红包封面,还不快来拿?
- Day8 - Python网络编程 Socket编程 --转自金角大王
- boost::json模块实现远程过程调用的测试程序
- C语言unit test单元测试类的实现(附完整源码)
- iOS8 【xcode6中添加pch全局引用文件】
- java stream 分组求和_Java stream List 求和、分组操作
- 【联盛德W806上手笔记】三、MCU系统与时钟结构
- Vue项目中使用基于pdf.js的vue-pdf插件在pc浏览器下阅览PDF文件
- 三层结构下的DBHelper方法
- 如何取消选中单选按钮?
- Atitit 编程语言知识点tech tree v2 attilax大总结
- 服务器迁移系统工具,win10如何用自带迁移工具迁移系统?_网站服务器运行维护,windows10,迁移系统...
- log2 3怎样用计算机打出,红警在局域网怎么样才可以2个人打多个电脑玩家?要打3个电脑以上的...
- 【立贴为证】二十年后2027,百度眼必然成人眼一个
- git did not exit cleanly (exit code 128)我个人解决方案
- 温度测量基于c语言,基于PN结的温度测量系统设计论文(C语言)--189876772.doc
- Axios源码深度剖析
- 全国计算机等级报名登记表,全国计算机等级考试报名报名流程
- 写给运维新手的十一条 Docker 守则,牢记!
- 深大计网实验 4:Socket 网络编程
热门文章
- java异步处理rest服务_异步处理rest服务
- 介质簇结构不正确_电动蝶阀的结构特征以及优点,值得看完
- 锁屏界面提示某些设置已隐藏_OPPO手机忘记锁屏密码怎么办?教你一招轻松解开!...
- LibFewShot:小样本学习与细粒度分类(一) -- 环境部署、相关论文研究
- python创建excel重复写入_Python小练习:创建并写入Excel
- deeplearning.ai——字符级语言模型-恐龙岛
- 自学TP5源码(一)
- Java 故障安全异常处理
- 数据绑定以及Container.DataItem几种方式与使用方法分析
- 电脑老是自动重启怎么回事??