c# 自定义解析JSON字符串数据
解析json字符串有很多方式, 1 : 在网上下载json解析的dll类库并添加引用, 调用相关方法; 2 : 使用自带类库javascriptserializer的序列号和反序列化; 对于以上两个方法我没有试用过, 应该很方便很简洁性能很高吧!
自己根据遍历字符串找json字符串规律, 自己写了一个类库, 只有一个方法只提供解析, 没有其他方法. 缺点 : 可能比较死板, 可能性能也不及网上下载解析类库.
经测试和调试后可以遍历大部分json字符串数据, json字符串可以嵌套, 但要符合json的规律, 数据中不能出现json字符串敏感关键字符 " 和 , 和 [ ] 和 { } ,数据中如果需要使用可以使用中文字符代替.
数据返回结果存放在 dictionary<string, object> 键 值对中, 如果 值为字符串, 那么object就为字符串,为了嵌套, 如果 值为数组, 那么object就为 list<object> , 如果值为一个对象, 那么object就存放在 dictionary<string, object> 如此嵌套下去, 最终数据我们根据自己的json数据结构遍历dictionary<string, object>集合即可. (注 : 每个dictionary中键必须唯一)
1. 解析类 : analyzejson 全部代码:
using system; using system.collections.generic; using system.linq; using system.text; namespace system.analyzejson { /// <summary> /// 对于 json数据进行解析 /// date:2019/6/25 /// author:weloglog /// </summary> public class analyzejson { /// <summary> /// 最大嵌套深度 /// </summary> public int maxnum = 50; /// <summary> /// 解析json字符串 /// </summary> /// <param name="strjson">json字符串</param> /// <returns>返回dictionary数据</returns> public dictionary<string, object> analyzestring(string strjson) { if (strjson == null || strjson.trim() == "" || strjson.trim().length < 0) { return null; } #region 筛选判断并赋值 [此步骤可以省略] int idf = -1;//第一个 { 下标索引 int idl = -1;//最后一个 } 下标索引 int md = 0;//记录 { } 的个数对 int mz = 0;//记录 [ ] 的个数对 for (int i = 0; i < strjson.length; i++) { if (md > maxnum || mz > maxnum) { break;//不满足条件退出循环 } if (idf == -1 && strjson[i] == '{') { idf = i;//取第一个 { 下标 } if (strjson[i] == '{') { md++; if (idl > 0) { break; } } if (strjson[i] == '}') { md--; if (md == 0) { idl = i; } } if (strjson[i] == '[') { mz++; } if (strjson[i] == ']') { mz--; } } if (md == 0 && mz == 0 && idl > 0 && idl - idf > 1) { strjson = strjson.substring(idf, idl - idf + 1);//重新赋值json字符串数据, 去掉{ }前后多余部分 } else { return null;//条件不满足, json字符串不规范 } #endregion //遍历 并返回 return obj(strjson); } //遇到 { } 的处理函数 private dictionary<string, object> obj(string str) { dictionary<string, object> ro = new dictionary<string, object>(); int dc = 0;//{ } 的对数 int len = str.length; for (int i = 0; i < len; i++) { if (str[i] == '{') { dc++; } if (str[i] == '}') { dc--; } if (str[i] != '{' && dc > 0) { stringbuilder tem = new stringbuilder(); stringbuilder ojtem = new stringbuilder(); bool isstr = false; object oj = ""; int c = 0;//次数 bool iskey = true;//是否为键赋值 bool isstring = true;//值是否为字符串类型 while (i < len && str[i] != ',') { if (iskey) //给键 赋值 { if (str[i] != '\"') { if (str[i] == ':') { iskey = false; c = -1;//重置 } else { //tem += str[i]; tem.append(str[i]); } } } else //给值 赋值 { //特殊情况, 遇到 { } 和 [ ] 的情况 if (isstring && str[i] == '[')//只允许第一次进入 { isstring = false; int idxs = 0;//记录 [ ] 出现的次数 stringbuilder tm = new stringbuilder(); while (i < len) { if (str[i] == '[') { idxs++; } if (str[i] == ']') { idxs--; } tm.append(str[i]); i++; if (idxs == 0)//变成一个完整的组合 { break; } } oj = arr(tm.tostring()); break; } else if (isstring && str[i] == '{')//只允许第一次进入 { isstring = false; int idxs = 0;//记录 { } 出现的次数 stringbuilder tm = new stringbuilder(); while (i < len) { if (str[i] == '{') { idxs++; } if (str[i] == '}') { idxs--; } tm.append(str[i]); i++; if (idxs == 0)//变成一个完整的组合 { break; } } oj = obj(tm.tostring()); break; } else { if (str[i] != '\"') { if (str[i] == ',' || str[i] == '}' || str[i] == ']')//跳出循环 { break; } else { isstr = true; ojtem.append(str[i]); } } } } c++; i++; } c = 0; try//键 唯一 { if (tem != null && tem.tostring().length > 0) { if (isstr) { ro.add(tem.tostring(), ojtem);//添加 isstr = false; } else { ro.add(tem.tostring(), oj);//添加 } } } catch { } } } return ro; } //遇到 [ ] 的处理函数 private object arr(string str) { object ojj = new object(); //去掉首位 [ ] 符号 str = str.substring(1, str.length - 2); int len = str.length; int c = 0;//双引号索引 list<object> lst = new list<object>(); bool ists = false;//是否为特殊 for (int i = 0; i < len; i++) { object tem = ""; stringbuilder sb = new stringbuilder(); bool isstr = false; while (i < len) { if (str[i] == '[')//特殊处理 { int idxs = 0;//记录 [ ] 出现的次数 stringbuilder tm = new stringbuilder(); while (i < len) { if (str[i] == '[') { idxs++; } if (str[i] == ']') { idxs--; } tm.append(str[i]); i++; if (idxs == 0)//变成一个完整的组合 { break; } } lst.add(arr(tm.tostring())); ists = true; i++; continue; } else if (str[i] == '{')//特殊处理 { int idxs = 0;//记录 [ ] 出现的次数 stringbuilder tm = new stringbuilder(); while (i < len) { if (str[i] == '{') { idxs++; } if (str[i] == '}') { idxs--; } tm.append(str[i]); i++; if (idxs == 0)//变成一个完整的组合 { break; } } lst.add(obj(tm.tostring())); ists = true; i++; continue; } else { ists = false; if (c == 0 && str[i] == '\"') { i++; c++; continue; } if (str[i] == '\"' && i + 1 < len && str[i + 1] == ',' || i + 1 == len) { i++; c++; break; } if (str[i] == '\"' && i + 1 < len && str[i + 1] == ']' || i + 1 == len) { i++; c++; continue; } if (i + 1 < len && str[i + 1] == ']') { i++; c++; continue; } isstr = true; sb.append(str[i]); i++; c++; } } if (!ists) { if (isstr) { lst.add(sb);// [ ] 的值存入list<string> 中 isstr = false; } else { lst.add(tem);// [ ] 的值存入list<string> 中 } } c = 0;//归零 } ojj = lst; return ojj; } } }
2. 方法的调用和数据的使用
using system; using system.collections.generic; using system.componentmodel; using system.data; using system.drawing; using system.analyzejson; using system.linq; using system.text; using system.threading.tasks; using system.windows.forms; using system.io; using system.text.regularexpressions; namespace windowsformsapplication1 { public partial class form1 : form { public form1() { initializecomponent(); } //按钮点击事件 private void button1_click(object sender, eventargs e) { // //窗体中一个 textbox 文本框[多行] 和 一个 button 测试按钮 // // //在网上随便找了一个json数据字符串的js //[在这里感谢'4399游戏资讯'平台提供的这些数据供测试,该js只供学习不可用作商业用途] // //该js是一个游戏类英雄相关属性的数据 //js共4行, 每一行数据也非常大, 我们使用第一行进行测试,每一行使用回车键[\n]分割 // string src = "//newsimg.5054399.com/dtzzq/static/zrmnq/wap/js/data.js"; streamreader reader = new streamreader(system.net.webrequest.create("http:" + src).getresponse().getresponsestream()); //regex.unescape("") 方法是将字符串含有 \uxxxx 的16进制转化为我们识别的字符 string[] zongstrs = regex.unescape(reader.readtoend()).split('\n'); //创建一个解析对象 analyzejson aj = new analyzejson(); //调用方法 analyzestring("json数据字符串") 进行解析 并返回 解析后的数据集合dictionary<string, object> dictionary<string, object> obj = aj.analyzestring(zongstrs[0]); //定义一个字符串进行拼接显示得到的数据 stringbuilder sb = new stringbuilder(); //调用拼接处理方法 zx(obj, sb); //把得到的数据以字符串的形式展示出来 textbox1.text = sb.tostring(); } // //数据遍历解析方法 //根据需要可以为自己定义数据处理赋值方法,此处只作为显示使用 // private void zx(dictionary<string, object> obj, stringbuilder sb) { foreach (var item in obj) { if ((item.value as dictionary<string, object>) != null) { zx((item.value as dictionary<string, object>), sb); } else { if ((item.value as list<object>) != null && (item.value as list<object>).count > 0) { list<object> lst = item.value as list<object>; sb.append(item.key + ":\r\n"); for (int i = 0; i < lst.count; i++) { if ((lst[i] as dictionary<string, object>) != null) { zx((lst[i] as dictionary<string, object>), sb); } else { sb.append("\t" + lst[i] + ","); } } sb.append("\r\n"); } else { sb.append(item.key + ":" + item.value.tostring() + "\r\n"); } } } } } }
代码可能还有很多需要改进的地方, 希望各位大神指出来, 共同学习进步!^_^
上一篇: C#使用回溯法解决背包问题实例分析
下一篇: C#实现窗口之间的传值