本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《
阿里云开发者社区用户服务协议
》和
《
阿里云开发者社区知识产权保护指引
》。如果您发现本社区中有涉嫌抄袭的内容,填写
侵权投诉表单
进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
距离上一篇文章,又过去一个多月了,近些时间,工作依旧很忙碌,除了管理方面的事,代码方面主要折腾三个事:
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
,仅方便自己使用。
夜已深,该闭眼去梦里的世界旅游了。
最后是本文的源码:
179
{
180
isError = state ==
0
|| (state ==
1
&& valueStart >
重复出现。
if
(arrayStart)
["aa,] [,] [{},{}]
184
isError = keyStart ==
0
&& !setDicValue;
185
}
186
}
break
;
[ "a",\r\n{} ]
break
;
default
:
值开头。。
isError = (!jsonStart && !arrayStart) || (state ==
0
&& keyStart == -
1
) || (valueStart == -
1
&& state ==
break
;
197
}
if (isError)
203
}
<summary>
设置字符状态(返回true则为关键词,返回false则当为普通字符处理)
</summary>
private
static
bool
SetCharState(
char
c,
ref
CharState cs)
208
{
209
cs.CheckIsError(c);
switch
(c)
211
{
[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
#region
大括号
if
(cs.keyStart <=
0
&& cs.valueStart <=
215
{
216
cs.keyStart =
217
cs.valueStart =
if
(cs.jsonStart && cs.state ==
219
{
220
cs.childrenStart =
true
;
221
}
223
{
224
cs.state =
225
}
226
cs.jsonStart =
true
;
return
true
;
228
}
#endregion
break
;
#region
大括号结束
if
(cs.keyStart <=
0
&& cs.valueStart <
2
&& cs.jsonStart)
234
{
235
cs.jsonStart =
false
;
正常结束。
cs.state =
237
cs.keyStart =
238
cs.valueStart =
239
cs.setDicValue =
true
;
return
true
;
241
}
cs.isError = !cs.jsonStart && cs.state == 0;
#endregion
break
;
#region
中括号开始
if
(!cs.jsonStart)
248
{
249
cs.arrayStart =
true
;
return
true
;
251
}
if
(cs.jsonStart && cs.state ==
253
{
254
cs.childrenStart =
true
;
return
true
;
256
}
#endregion
break
;
#region
中括号结束
if
(cs.arrayStart && !cs.jsonStart && cs.keyStart <=
2
&& cs.valueStart <=
[{},333]
这样结束。
263
cs.keyStart =
264
cs.valueStart =
265
cs.arrayStart =
false
;
return
true
;
267
}
#endregion
break
;
#region
引号
if
(cs.jsonStart || cs.arrayStart)
274
{
if
(cs.state ==
key阶段,有可能是数组["aa",{}]
if
(cs.keyStart <=
278
{
279
cs.keyStart = (c ==
return
true
;
281
}
if
((cs.keyStart ==
2
&& c ==
'
) || (cs.keyStart ==
3
&& c ==
283
{
if
(!cs.escapeChar)
285
{
286
cs.keyStart = -
return
true
;
288
}
290
{
291
cs.escapeChar =
false
;
292
}
293
}
294
}
if
(cs.state ==
1
&& cs.jsonStart)
值阶段必须是Json开始了。
if
(cs.valueStart <=
298
{
299
cs.valueStart = (c ==
return
true
;
301
}
if
((cs.valueStart ==
2
&& c ==
'
) || (cs.valueStart ==
3
&& c ==
303
{
if
(!cs.escapeChar)
305
{
306
cs.valueStart = -
return
true
;
308
}
310
{
311
cs.escapeChar =
false
;
312
}
313
}
315
}
316
}
#endregion
break
;
#region
冒号
if
(cs.jsonStart && cs.keyStart <
2
&& cs.valueStart <
2
&& cs.state ==
322
{
if
(cs.keyStart ==
324
{
325
cs.keyStart = -
326
}
327
cs.state =
return
true
;
329
}
cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1);
#endregion
break
;
#region
逗号
["aa",{aa:12,}]
if
(cs.jsonStart)
337
{
if
(cs.keyStart <
2
&& cs.valueStart <
2
&& cs.state ==
339
{
340
cs.state =
341
cs.keyStart =
342
cs.valueStart =
if (cs.valueStart == 1)
cs.valueStart = 0;
cs.setDicValue =
true
;
return
true
;
349
}
350
}
if
(cs.arrayStart && cs.keyStart <=
352
{
353
cs.keyStart =
if (cs.keyStart == 1)
cs.keyStart = -1;
return
true
;
359
}
#endregion
break
;
[ "a",\r\n{} ]
if
(cs.keyStart <=
0
&& cs.valueStart <=
cs.jsonStart &&
return
true
;
跳过空格。
break
;
default
:
值开头。。
if
(c ==
if
(cs.escapeChar)
376
{
377
cs.escapeChar =
false
;
378
}
380
{
381
cs.escapeChar =
true
;
return
true
;
383
}
384
}
386
{
387
cs.escapeChar =
false
;
388
}
if
(cs.jsonStart || cs.arrayStart)
Json 或数组开始了。
if
(cs.keyStart <=
0
&& cs.state ==
392
{
393
cs.keyStart =
if
(cs.valueStart <=
0
&& cs.state ==
1
&& cs.jsonStart)
只有Json开始才有值。
397
cs.valueStart =
399
}
break
;
401
}
return
false
;
403
}
404
}
405
}
距离上一篇文章,又过去一个多月了,近些时间,工作依旧很忙碌,除了管理方面的事,代码方面主要折腾三个事:
1:开发框架(一整套基于配置型的开发体系框架)
2:CYQ.Data 数据层框架(持续的更新,最近也加入了Sybase的支持)
3:工作流流程图设计器。