相关文章推荐
俊逸的罐头  ·  VBA实战技巧09: ...·  1 年前    · 
睡不着的抽屉  ·  excel ...·  1 年前    · 
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

距离上一篇文章,又过去一个多月了,近些时间,工作依旧很忙碌,除了管理方面的事,代码方面主要折腾三个事:

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:工作流流程图设计器。