Catalog
1 Requirement Description
A batch of JSON-like strings without quotation marks were encountered in the project:
{Name:Heal,Age:20,Tag:[Coding,Reading]}
It needs to be parsed into JSON objects and then inserted into Elastic search to be stored as objects of type Object.
After comparing FastJson of Ali with Gson of Google, I couldn't find the function I wanted (maybe the blogger was not careful enough and had a message about children's learning to tell me about it). So I wrote a tool class to fulfill this requirement.
If it is a standard JSON string with quotation marks, it can be parsed directly through the above two tools. The method of use can be referred to:
Java - Two ways to format output JSON strings
2 parse code
2.1 Implementation Ideas
The main ideas of the code are explained in the annotations. The main ideas are as follows:
(1) Stack is used to count the [], {} symbols at the beginning and end of the string -- [] for List and {} for Map.
(2) Use String subString () method to reduce the parsed string;
(3) The internal List and Map objects are parsed recursively.
(4) For ease of processing, the smallest key-value is resolved to String type.
It should be noted that there should be no meaningless {,}, [,] symbols inside the string to be parsed, otherwise the parsing will be abnormal.
—— I haven't thought of a good compatibility method for the time being. If you have any ideas about pediatrics, please leave a message directly. **
2.2 Detailed Code
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 Parsing Unquoted JSON Strings * * @author Heal Chow * @date 2019/08/13 11:36 */ public class ParseJsonStrUtils { public static void main(String[] args) { // Quoted strings treat strings as part of key-value, so such strings are recommended to be converted using tools such as fastJson, Gson, and so on. // Note: There should be no meaningless {,}, [,] symbols inside String - no 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\"]" + "}}";*/ // Unquoted strings, the beginning and end of many pairs of [], {} do not affect parsing String sourceStr = "[[[{" + "{" + "Type:1," + "StoragePath:[{Name:/image/2019-08-01/15.jpeg,DeviceID:4401120000130},{ShotTime:2019-08-01 14:44:24}]," + "Width:140" + "}," + "{" + "Type:2,StoragePath:9090/pic/2019_08_01/src.jpeg," + "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("Error: " + e.getMessage()); e.printStackTrace(); } if (obj instanceof List) { jsonArray = (List<Map<String, Object>>) obj; System.out.println("Parsing generates List object: " + jsonArray); } else if (obj instanceof Map) { jsonMap = (Map<String, Object>) obj; System.out.println("Parsing generates Map object: " + jsonMap); } else { System.out.println("Strings that need to be parsed are neither JSON Array, And it doesn't fit. JSON Object!\n Original string: " + sourceStr); } } /** * Resolve Json-formatted strings, encapsulate them as List or Map, and return them * Note: (1) key and value cannot contain ",", key cannot contain ":" - separated by "," "and":", respectively. * (2) The string to be parsed must conform to the JSON object format, and only the outermost multi-layer nesting is handled simply. * Complex examples such as {a:b},{x:y} will not be fully recognized - the correct ones should be [{a:b},{x:y}]. * @param sourceStr A string surrounded by "[]" or "{}" * @return Generated JsonObject */ public static Object parseJson(String sourceStr) throws InvalidParameterException { if (sourceStr == null || "".equals(sourceStr)) { return sourceStr; } // Determine whether there are redundant matching "[]" and "{}" at the beginning and end of a string String parsedStr = simplifyStr(sourceStr, "[", "]"); parsedStr = simplifyStr(parsedStr, "{", "}"); // Implementing the entry and exit of "[]" and "{}" with the help of stack 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); // The interior of parsedStr may also be a continuous'{}}' parsedStr = simplifyStr(parsedStr, "{", "}"); } else { throw new InvalidParameterException("There is a mismatch in the string to parse'[]'or'{}', Please check!\n The original string is: " + sourceStr); } // Save the result of parsing. jsonArray may contain only String, or 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); // Judging whether JSON Array is empty if (jsonArray.size() > 0) { return jsonArray; } else { return jsonMap; } } /** * Loop parsing 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 according to "." String[] allKeyValues = parsedStr.split(","); if (allKeyValues.length > 0) { // Traverse and parse separately according to ":" out: for (String keyValue : allKeyValues) { // If the keyValue contains ":", indicating that the keyValue is an object in List < Map>, it is necessary 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 "[", and if so, the stack String key = keyValue.substring(0, index); while (key.startsWith("[") || key.startsWith("{")) { leftSymbolStack.push(key.substring(0, 1)); // The parsed string should be followed up all the time. parsedStr = parsedStr.substring(1); key = key.substring(1); } // Whether Interpretation and value Start with "[" - Another List Object - Recursive Resolution 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 if it exists. parsedStr = parsedStr.substring(innerIndex + 1); if (parsedStr.indexOf(",") == 0) { parsedStr = parsedStr.substring(1); } // This internal object, the internal "," has been parsed, to correct according to "," the cut string array, and continue to traverse. innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); break; } // Whether Interpretation and value Begin with'{''-- Another Map Object -- Recursive Resolution 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 if it exists. parsedStr = parsedStr.substring(innerIndex + 1); if (parsedStr.indexOf(",") == 0) { parsedStr = parsedStr.substring(1); } // This internal object, the internal "," has been parsed, to correct according to "," the cut string array, and continue to traverse. innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); break; } // Finally, determine whether the value tail contains "]" or "}" else { while (value.endsWith("]") || value.endsWith("}")) { // The rightmost character String right = value.substring(value.length() - 1); // At this point, the top element of the stack String top = leftSymbolStack.peek(); // If there is a match, then stack, otherwise ignore 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 if it exists. parsedStr = parsedStr.substring(key.length() + 1 + value.length() + 1); if (parsedStr.indexOf(",") == 0) { parsedStr = parsedStr.substring(1); } // When an object is parsed, the element is added to the List and a new object is created. jsonArray.add(jsonMap); jsonMap = new HashMap<>(16); // Continue with the analysis of the outer layer continue out; } // If they do not match, they 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 ":", which means that the keyValue is only a string in List < String > but not a Map in List < Map >, it can be added directly to List. else { jsonArray.add(keyValue); } } // The end of traversal and the final symbolic problem: judging whether the left stack matches the right stack or not 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 incoming string cannot be parsed JSON object!\n The original string is: " + parsedStr); } } } } } /** * Simplify the string by judging whether there are redundant matching "[]" and "{}" at 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 is still "[" or "{", then judge whether the penultimate is "]" or "}" - indicating that the length is at least 3, there will be no IndexOutOfBoundsException. if (second.equals(firstSymbol)) { String penultimate = sourceStr.substring(sourceStr.length() - 2, sourceStr.length() - 1); if (penultimate.equals(lastSymbol)) { // Shorten the string to parse sourceStr = sourceStr.substring(1, sourceStr.length() - 1); } else { break; } } else { break; } } return sourceStr; } }
2.3 Test Sample
(1) Quoted test:
// Test string: 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\"]" + "}}";
The analytical results are as follows:
(2) Test without quotation marks:
// Test string: String sourceStr = "[[[{" + "{" + "Type:1," + "StoragePath:[{Name:/image/2019-08-01/15.jpeg,DeviceID:4401120000130},{ShotTime:2019-08-01 14:44:24}]," + "Width:140" + "}," + "{" + "Type:2,StoragePath:9090/pic/2019_08_01/src.jpeg," + "Inner:{DeviceID:44011200}," + "Test:[{ShotTime:2019-08-01 14:50:14}]," + "Width:5600}" + "}}]]]";
The analytical results are as follows:
Copyright Statement
Authors: Thin Wind (https://healchow.com)
Origin: Blog Garden Thin Wind Blog (https://www.cnblogs.com/shoufeng)
Thank you for reading. If the article helps or inspires you, click[ Good writing should go to the top (vii) ] Or[ Recommendations (1) ] Let's go.
Copyright of this article belongs to the blogger. Reprint is welcome, but [link of the original text must be marked clearly on the article page]. Otherwise, the blogger reserves the right to pursue the legal responsibility of the relevant personnel.