识别Json字符串并分隔成Map集合
前言:
最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本。
过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案。
遇到的C#转Java的一些小问题:
1:C#的ref:这个参数的主要意图是:
就算方法内部重新对参数重新(new)赋值,也能保证外部的参数指向新的值。
Java木有了,不知道新的方案是什么?还是说只能避免方法内部重新(new)赋值?
2:C#的out:这个参数的主要意图是:
处理多值返回的问题。
Java木有了,只能改返回数组了。
3:C#的SqlDbType和DbType
其实我也没想过C#为什么还要搞个DbType(用在DbParameter参数上使用)
Java:涉入不深,不知道用啥代替?
4:C#的DBNull.Value
Java:好像木有这东东,用啥代替?
5:C#的ChangeType 通用类型转换
Java:涉入不深,不知道用啥代替?
6:C#的反射Type有属性可以识别是否泛型(IsGenericType)和Nullable.GetUnderlyingType(t)
Java:在Class里找不到泛型判断,替代方案是?
7:发现Map集合的大多数默认都对key进行了排序,最后发现只有这个才默认没排序:LinkedHashMap
8:关于代码折叠:
C#里用#region和#endregion。
Java里要下个插件,然后改成//region和//endregion。
9:Java木有Internal修饰符,木有Jar包内使用的修饰符,真心不友好。
10:其它的主是一些大小写和方法的改了。
好了,先小小总结到这里,下面上Java代码,主要有3个类:
1:实现代码(内部实现类):CharState
package cyq.data.tool; /// <summary> /// 字符状态 /// </summary> class CharState { boolean jsonStart = false;//以 "{"开始了... boolean setDicValue = false;// 可以设置字典值了。 boolean escapeChar = false;//以"\"转义符号开始了 /// <summary> /// 数组开始【仅第一开头才算】,值嵌套的以【childrenStart】来标识。 /// </summary> boolean arrayStart = false;//以"[" 符号开始了 boolean childrenStart = false;//子级嵌套开始了。 /// <summary> /// 【0 取名称中】;【1 取值中】 /// </summary> int state = -1; /// <summary> /// 【-1 未初始化】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】 /// </summary> int keyStart = -1; /// <summary> /// 【-1 未初始化】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】 /// </summary> int valueStart = -1; boolean isError = false;//是否语法错误。 void CheckIsError(char c)//只当成一级处理(因为GetLength会递归到每一个子项处理) { switch (c) { case ‘{‘://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}] isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。 break; case ‘}‘: isError = !jsonStart || (keyStart > -1 && state == 0);//重复结束错误 或者 提前结束。 break; case ‘[‘: isError = arrayStart && state == 0;//重复开始错误 break; case ‘]‘: isError = !arrayStart;//重复开始错误 break; case ‘"‘: case ‘\‘‘: isError = !jsonStart;//未开始Json break; case ‘:‘: isError = !jsonStart || (jsonStart && keyStart < 2 && valueStart < 2 && state == 1);//未开始Json 同时 只能处理在取值之前。 break; case ‘,‘: isError = (!jsonStart && !arrayStart) || (jsonStart && keyStart < 2 && valueStart < 2 && state == 0);//未开始Json 同时 只能处理在取值之后。 break; default: //值开头。。 isError = !jsonStart || (keyStart == 0 && valueStart == 0 && state == 0);// break; } //if (isError) //{ //} } }
2:实现代码(内部实现类):JsonSplit
PS:Log这个类的代码可以先注释屏蔽。
package cyq.data.tool; import java.util.*; import cyq.data.Log; public class JsonSplit { public static boolean IsJson(String json) { return IsJsonAndBackIndex(json)==-1; } public static int IsJsonAndBackIndex(String json) { if(json==null || json.isEmpty() || json.length()==1) { return 0; } if ((json.charAt(0) == ‘{‘ && json.charAt(json.length() - 1) == ‘}‘) || (json.charAt(0)== ‘[‘ && json.charAt(json.length() - 1)== ‘]‘)) { int errIndex = 0; CharState cs = new CharState(); char c; for (int i = 0; i < json.length(); i++) { c = json.charAt(i); if (SetCharState(c, cs) && cs.childrenStart)//设置关键符号状态。 { String item = json.substring(i); int[] v=GetValueLength(item, true); int length = v[0]; int err=v[1]; cs.childrenStart = false; if (err > 0) { errIndex = i + err; return errIndex; } i = i + length - 1; } if (cs.isError) { errIndex = i; return errIndex; } } if( !cs.arrayStart && !cs.jsonStart) { return -1; } return errIndex; } else { return 0; } } static List<LinkedHashMap<String, String>> Split(String json) { List<LinkedHashMap<String, String>> result = new ArrayList<LinkedHashMap<String, String>>(); if (json!=null && !json.isEmpty()) { LinkedHashMap<String, String> dic = new LinkedHashMap<String, String>(); String key = ""; StringBuilder value = new StringBuilder(); CharState cs = new CharState(); try { //region 核心逻辑 char c; for (int i = 0; i < json.length(); i++) { c = json.charAt(i); if (!SetCharState(c, cs))//设置关键符号状态。 { if (cs.jsonStart)//Json进行中。。。 { if (cs.keyStart > 0) { key += c; } else if (cs.valueStart > 0) { value.append(c); //value += c; } } else if (!cs.arrayStart)//json结束,又不是数组,则退出。 { break; } } else if (cs.childrenStart)//正常字符,值状态下。 { String item = json.substring(i); int[] v= GetValueLength(item, false); int length =v[0]; //int temp=v[1]; //value = item.SubString(0, length); value.setLength(0); value.append(item.substring(0, length)); cs.childrenStart = false; cs.valueStart = 0; //cs.state = 0; cs.setDicValue = true; i = i + length - 1; } if (cs.setDicValue)//设置键值对。 { if (key!=null && !key.isEmpty() && !dic.containsKey(key)) { //if (value != String.Empty) //{ boolean isNull = json.charAt(i - 5) == ‘:‘ && json.charAt(i) != ‘"‘ && value.length() == 4 && value.toString() == "null"; if (isNull) { value.setLength(0); } dic.put(key, value.toString()); //} } cs.setDicValue = false; key = ""; value.setLength(0); } if (!cs.jsonStart && dic.size() > 0) { result.add(dic); if (cs.arrayStart)//处理数组。 { dic = new LinkedHashMap<String, String>(); } } } //endregion } catch (Exception err) { Log.WriteLogToTxt(err); } finally { key = null; value.setLength(0); value = null; } } return result; } /// <summary> /// 获取值的长度(当Json值嵌套以"{"或"["开头时) /// </summary> private static int[] GetValueLength(String json, boolean breakOnErr) { int errIndex = 0; int len = 0; if (json!=null && !json.isEmpty()) { CharState cs = new CharState(); char c; for (int i = 0; i < json.length(); i++) { c = json.charAt(i); if (!SetCharState(c, cs))//设置关键符号状态。 { if (!cs.jsonStart && !cs.arrayStart)//json结束,又不是数组,则退出。 { break; } } else if (cs.childrenStart)//正常字符,值状态下。 { int[] v=GetValueLength(json.substring(i), breakOnErr);//递归子值,返回一个长度。。。 int length = v[0]; errIndex=v[1]; cs.childrenStart = false; cs.valueStart = 0; //cs.state = 0; i = i + length - 1; } if (breakOnErr && cs.isError) { errIndex = i; break; } if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。 { len = i + 1;//长度比索引+1 break; } } } int[] valueAndErrIndex=new int[2]; valueAndErrIndex[0]=len; valueAndErrIndex[1]=errIndex; return valueAndErrIndex; } /// <summary> /// 设置字符状态(返回true则为关键词,返回false则当为普通字符处理) /// </summary> private static boolean SetCharState(char c, CharState cs) { switch (c) { case ‘{‘://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}] if (cs.keyStart <= 0 && cs.valueStart <= 0) { cs.CheckIsError(c); if (cs.jsonStart && cs.state == 1) { cs.valueStart = 0; cs.childrenStart = true; } else { cs.state = 0; } cs.jsonStart = true;//开始。 return true; } break; case ‘}‘: if (cs.keyStart <= 0 && cs.valueStart < 2) { cs.CheckIsError(c); if (cs.jsonStart) { cs.jsonStart = false;//正常结束。 cs.valueStart = 0; cs.setDicValue = true; } return true; } // cs.isError = !cs.jsonStart && cs.state == 0; break; case ‘[‘: if (!cs.jsonStart) { cs.CheckIsError(c); cs.arrayStart = true; return true; } else if (cs.jsonStart && cs.state == 1 && cs.valueStart < 2) { cs.CheckIsError(c); //cs.valueStart = 1; cs.childrenStart = true; return true; } break; case ‘]‘: if (!cs.jsonStart && cs.keyStart <= 0 && cs.valueStart <= 0) { cs.CheckIsError(c); if (cs.arrayStart)// && !cs.childrenStart { cs.arrayStart = false; } return true; } break; case ‘"‘: case ‘\‘‘: cs.CheckIsError(c); if (cs.jsonStart) { if (cs.state == 0)//key阶段 { cs.keyStart = (cs.keyStart <= 0 ? (c == ‘"‘ ? 3 : 2) : 0); return true; } else if (cs.state == 1)//值阶段 { if (cs.valueStart <= 0) { cs.valueStart = (c == ‘"‘ ? 3 : 2); return true; } else if ((cs.valueStart == 2 && c == ‘\‘‘) || (cs.valueStart == 3 && c == ‘"‘)) { if (!cs.escapeChar) { cs.valueStart = 0; return true; } else { cs.escapeChar = false; } } } } break; case ‘:‘: cs.CheckIsError(c); if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0) { cs.keyStart = 0; cs.state = 1; return true; } // cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1); break; case ‘,‘: cs.CheckIsError(c); if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1) { cs.state = 0; cs.valueStart = 0; cs.setDicValue = true; return true; } else if (cs.arrayStart && !cs.jsonStart) { return true; } break; case ‘ ‘: case ‘\r‘: case ‘\n‘: if (cs.jsonStart && cs.keyStart <= 0 && cs.valueStart <= 0) { return true;//跳过空格。 } break; default: //值开头。。 cs.CheckIsError(c); if (c == ‘\\‘) //转义符号 { if (cs.escapeChar) { cs.escapeChar = false; } else { cs.escapeChar = true; return true; } } else { cs.escapeChar = false; } if (cs.jsonStart) { if (cs.keyStart <= 0 && cs.state <= 0) { cs.keyStart = 1;//无引号的 } else if (cs.valueStart <= 0 && cs.state == 1) { cs.valueStart = 1;//无引号的 } } break; } return false; } }
3:实现代码(外部调用类):JsonHelper
package cyq.data.tool; import java.util.*; public class JsonHelper { /// <summary> /// 检测是否Json格式的字符串 /// </summary> /// <param name="json">要检测的字符串</param> public static boolean IsJson(String json) { return JsonSplit.IsJson(json); } /// <summary> /// 将Json分隔成键值对。 /// </summary> public static Map<String, String> Split(String json) { List<LinkedHashMap<String, String>> result = JsonSplit.Split(json); if (result != null && result.size() > 0) { return result.get(0); } return null; } /// <summary> /// 将Json 数组分隔成多个键值对。 /// </summary> public static List<LinkedHashMap<String, String>> SplitArray(String jsonArray) { if (jsonArray==null || jsonArray.isEmpty()) { return null; } jsonArray = jsonArray.trim(); return JsonSplit.Split(jsonArray); } }
4:实现代码(单元测试类):JsonTest
PS:标签Key没用引号,所以识别是false,但Split方法是兼容不严格模式的,所以还能分成Map。
总结:
总体而言,虽然Java很原始,C#很高级,但技术这东西,走向一个极端后,也得学学大闸蟹,得横着走。
只有两手抓,两手都硬的时候,才不会被技术所孤立。。。
时间: 2024-10-04 17:24:03