web123456

Java manually parsing JSON strings without quotes

package com.healchow.util; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; /** * Java parses JSON strings without quotes * * @author Heal Chow * @date 2019/08/13 11:36 */ public class ParseJsonStrUtils { public static void main(String[] args) { // Quoted strings will treat the string as part of the key-value, so it is recommended to convert these strings using fastJson, Gson and other tools. // Note: There should be no meaningless {,}, [,] symbols inside String - I didn't think of a good compatibility method for the time being /*String sourceStr = "{\"_index\":\"book_shop\"," + "\"_id\":\"1\"," + "\"_source\":{" + "\"name\":\"Thinking in Java [4th Edition]\"," + "\"author\":\"[US] Bruce Eckel\"," + "\"price\":109.0,\"date\":\"2007-06-01 00:00:00\"," + "\"tags\":[\"Java\",[\"Programming\"]" + "}}";*/ // String without quotes, multiple pairs of [] and {} will not affect the parsing String sourceStr = "[[[{" + "{" + "Type:1," + "StoragePath:[{Name:/image/2019-08-01/,DeviceID:4401120000130},{ShotTime:2019-08-01 14:44:24}]," + "Width:140" + "}," + "{" + "Type:2,StoragePath:9090/pic/2019_08_01/," + "Inner:{DeviceID:44011200}," + "Test:[{ShotTime:2019-08-01 14:50:14}]," + "Width:5600}" + "}}]]]"; List<Map<String, Object>> jsonArray; Map<String, Object> jsonMap; Object obj = null; try { obj = parseJson(sourceStr); } catch (Exception e) { System.out.println("An error occurred: " + e.getMessage()); e.printStackTrace(); } if (obj instanceof List) { jsonArray = (List<Map<String, Object>>) obj; System.out.println("The parsed list object is generated: " + jsonArray); } else if (obj instanceof Map) { jsonMap = (Map<String, Object>) obj; System.out.println("The Map object was generated by parsing: " + jsonMap); } else { System.out.println("The string that needs to be parsed is neither JSON Array nor conforms to JSON Object!\nOriginal string: " + sourceStr); } } /** * Parses strings in Json format, encapsulate as List or Map and returns * Note: (1) The key and value cannot contain ",", and the key cannot contain ":" - Use "," and ":" to separate them separately. * (2) The string to be parsed must conform to the format of the JSON object, and only the outermost multi-layer nesting is simply processed. * Complex things such as "{a:b},{x:y}" will not be fully recognized - the correct one should be "[{a:b},{x:y}]" * @param sourceStr String surrounded by "[]" or "{}" at the beginning and end * @return generated JsonObject */ public static Object parseJson(String sourceStr) throws InvalidParameterException { if (sourceStr == null || "".equals(sourceStr)) { return sourceStr; } // Determine whether there are redundant and matching "[]" and "{}" at the beginning and end of the string String parsedStr = simplifyStr(sourceStr, "[", "]"); parsedStr = simplifyStr(parsedStr, "{", "}"); // Use the stack to achieve the entry and departure of "[]" and "{}" Stack<String> leftSymbolStack = new Stack<>(); Stack<String> rightSymbolStack = new Stack<>(); if ((parsedStr.startsWith("[") && parsedStr.endsWith("]")) || (parsedStr.startsWith("{") && parsedStr.endsWith("}"))) { leftSymbolStack.push(parsedStr.substring(0, 1)); rightSymbolStack.push(parsedStr.substring(parsedStr.length() - 1)); parsedStr = parsedStr.substring(1, parsedStr.length() - 1); // parsedStr may also be continuous inside "{{}}" parsedStr = simplifyStr(parsedStr, "{", "}"); } else { throw new InvalidParameterException("There is a mismatch '[]' or '{}' in the string to be parsed, please check!\nThe original string is: " + sourceStr); } // Save the parsed result. jsonArray may only have String, or may contain Map<String, Object> List<Object> jsonArray = new ArrayList<>(); Map<String, Object> jsonMap = new HashMap<>(16); // Internal traversal and analysis innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); // Determine whether jsonArray is empty if (jsonArray.size() > 0) { return jsonArray; } else { return jsonMap; } } /** * Looping to parse the internal List and Map objects */ private static void innerParseByLoop(String parsedStr, Stack<String> leftSymbolStack, Stack<String> rightSymbolStack, List<Object> jsonArray, Map<String, Object> jsonMap) throws InvalidParameterException { if (parsedStr == null || parsedStr.equals("")) { return; } // Separate by "," String[] allKeyValues = parsedStr.split(","); if (allKeyValues.length > 0) { // traverse, and parse according to ":" out: for (String keyValue : allKeyValues) { // If the keyValue contains ":", it means that the keyValue is an object in List<Map>, you need to determine the location of the first ":" - there may be multiple ":" int index = keyValue.indexOf(":"); if (index > 0) { // Determine whether the key still starts with "{" or "[", if so, press the stack String key = keyValue.substring(0, index); while (key.startsWith("[") || key.startsWith("{")) { leftSymbolStack.push(key.substring(0, 1)); // The parsed string must be followed up parsedStr = parsedStr.substring(1); key = key.substring(1); } // Whether the interpretation and value begins with "[" — another List object — recursive analysis String value = keyValue.substring(index + 1); if (value.startsWith("[")) { int innerIndex = parsedStr.indexOf("]"); List<Object> innerList = (List<Object>) parseJson(parsedStr.substring(key.length() + 1, innerIndex + 1)); jsonMap.put(key, innerList); // Clear the last "]" and determine whether "," parsedStr = parsedStr.substring(innerIndex + 1); if (parsedStr.indexOf(",") == 0) { parsedStr = parsedStr.substring(1); } // This internal object has been parsed, and the string array cut according to "," must be corrected and continued to traverse innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); break; } // Whether the interpretation and value starts with "{" - another Map object - recursive analysis else if (value.startsWith("{")) { int innerIndex = parsedStr.indexOf("}"); Map<String, Object> innerMap = (Map<String, Object>) parseJson(parsedStr.substring(key.length() + 1, innerIndex + 1)); jsonMap.put(key, innerMap); // Clear the last "}" and determine whether there is "," parsedStr = parsedStr.substring(innerIndex + 1); if (parsedStr.indexOf(",") == 0) { parsedStr = parsedStr.substring(1); } // This internal object has been parsed, and the string array cut according to "," must be corrected and continued to traverse innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); break; } // Finally determine whether the value end contains "]" or "}" else { while (value.endsWith("]") || value.endsWith("}")) { // The character on the far right String right = value.substring(value.length() - 1); // At this time, the top element of the stack String top = leftSymbolStack.peek(); // If there is a matching one, the stack will be popped, otherwise it will be ignored if (("}".equals(right) && "{".equals(top)) || ("]".equals(right) && "[".equals(top))) { leftSymbolStack.pop(); value = value.substring(0, value.length() - 1); jsonMap.put(key, value); // Clear the last "}" and determine whether there is "," parsedStr = parsedStr.substring(key.length() + 1 + value.length() + 1); if (parsedStr.indexOf(",") == 0) { parsedStr = parsedStr.substring(1); } // After parsing an object, add the element to the List and create a new object jsonArray.add(jsonMap); jsonMap = new HashMap<>(16); // Continue to analyze the outer layer continue out; } // If none of them match, it may be the last symbol of the source string else { rightSymbolStack.push(right); value = value.substring(0, value.length() - 1); } } jsonMap.put(key, value); int length = key.length() + value.length() + 2; if (parsedStr.length() > length) { parsedStr = parsedStr.substring(length); } else { parsedStr = ""; } } } // If the keyValue does not contain ":", it means that the keyValue is just a string in List<String>, not a Map in List<Map>, then add it directly to the List else { jsonArray.add(keyValue); } } // The traversal ends, dealing with the last symbol problem - determine whether the left and right stacks match while (!leftSymbolStack.empty()) { if (leftSymbolStack.peek().equals("{") && parsedStr.equals("}")) { leftSymbolStack.pop(); } if (!rightSymbolStack.empty()) { if (leftSymbolStack.peek().equals("{") && rightSymbolStack.peek().equals("}")) { leftSymbolStack.pop(); rightSymbolStack.pop(); } else if (leftSymbolStack.peek().equals("[") && rightSymbolStack.peek().equals("]")) { leftSymbolStack.pop(); rightSymbolStack.pop(); } else { throw new InvalidParameterException("The passed string cannot be parsed into a JSON object!\nThe original string is: " + parsedStr); } } } } } /** * Simplify whether there are redundant and matching "[]" and "{}" in the beginning and end of the string. */ private static String simplifyStr(String sourceStr, String firstSymbol, String lastSymbol) { while (sourceStr.startsWith(firstSymbol) && sourceStr.endsWith(lastSymbol)) { String second = sourceStr.substring(1, 2); // If the second one is still "[" or "{", then determine whether the second last one is "]" or "}" - It means that the length is at least 3, and no IndexOutOfBoundsException will occur if (second.equals(firstSymbol)) { String penultimate = sourceStr.substring(sourceStr.length() - 2, sourceStr.length() - 1); if (penultimate.equals(lastSymbol)) { // Shorten the string to be parsed sourceStr = sourceStr.substring(1, sourceStr.length() - 1); } else { break; } } else { break; } } return sourceStr; } }