Last active
August 23, 2021 06:19
-
-
Save komamitsu/a44835879b04829892f9c56db94d1f45 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
class JsonParser { | |
private Object parsePrimitive(StringTokenizer tokenizer, String token) { | |
if (token.startsWith("\"")) { | |
if (token.endsWith("\"")) { | |
return token.subSequence(1, token.length() - 1); | |
} | |
StringBuilder builder = new StringBuilder(token); | |
while (tokenizer.hasMoreTokens()) { | |
token = tokenizer.nextToken(); | |
if (token.endsWith("\"")) { | |
return builder.append(token).subSequence(1, builder.length() - 1).toString(); | |
} | |
builder.append(token); | |
} | |
throw new RuntimeException(String.format("Invalid String: %s", builder)); | |
} | |
else { | |
try { | |
return Long.parseLong(token); | |
} | |
catch (NumberFormatException e) { | |
return Double.parseDouble(token); | |
} | |
} | |
} | |
private String parseKey(StringTokenizer tokenizer, String firstToken) { | |
Object primitive = parsePrimitive(tokenizer, firstToken); | |
if (primitive instanceof String) { | |
return (String) primitive; | |
} | |
throw new RuntimeException(String.format("key should be String: %s", primitive)); | |
} | |
private void invalidStateAndInput(ObjectParseState state, String token) { | |
throw new RuntimeException(String.format("Unexpected input. state: %s, input: %s", state, token)); | |
} | |
private Object parseValue(StringTokenizer tokenizer, String token) { | |
if (token.equals("{")) { | |
return parseObject(tokenizer); | |
} | |
else if (token.equals("[")) { | |
return parseArray(tokenizer); | |
} | |
else { | |
return parsePrimitive(tokenizer, token); | |
} | |
} | |
private Map<String, Object> parseObject(StringTokenizer tokenizer) { | |
ObjectParseState state = ObjectParseState.PARSE_KEY; | |
Map<String, Object> obj = new HashMap<>(); | |
String key = null; | |
while (tokenizer.hasMoreTokens()) { | |
String token = tokenizer.nextToken().trim(); | |
if (token.isEmpty()) { | |
continue; | |
} | |
switch (state) { | |
case PARSE_KEY: | |
if (token.equals("}")) { | |
// Empty obj | |
return obj; | |
} | |
key = parseKey(tokenizer, token); | |
state = ObjectParseState.PARSE_COLON; | |
break; | |
case PARSE_COLON: | |
if (token.equals(":")) { | |
state = ObjectParseState.PARSE_VALUE; | |
} | |
else { | |
invalidStateAndInput(state, token); | |
} | |
break; | |
case PARSE_VALUE: | |
obj.put(key, parseValue(tokenizer, token)); | |
state = ObjectParseState.PARSE_COMMA; | |
break; | |
case PARSE_COMMA: | |
if (token.equals("}")) { | |
return obj; | |
} | |
else if (token.equals(",")) { | |
state = ObjectParseState.PARSE_KEY; | |
} | |
else { | |
invalidStateAndInput(state, token); | |
} | |
break; | |
default: | |
invalidStateAndInput(state, token); | |
break; | |
} | |
} | |
throw new RuntimeException("Incomplete object"); | |
} | |
private List<Object> parseArray(StringTokenizer tokenizer) { | |
List<Object> array = new ArrayList<>(); | |
boolean waitValue = true; | |
while (tokenizer.hasMoreTokens()) { | |
String token = tokenizer.nextToken().trim(); | |
if (token.isEmpty()) { | |
continue; | |
} | |
if (waitValue) { | |
array.add(parseValue(tokenizer, token)); | |
waitValue = false; | |
} | |
else { | |
if (token.equals("]")) { | |
return array; | |
} | |
else if (token.equals(",")) { | |
waitValue = true; | |
} | |
else { | |
throw new RuntimeException("A comma is missing in an array"); | |
} | |
} | |
} | |
throw new RuntimeException("Incomplete array"); | |
} | |
Object parse(String s) { | |
StringTokenizer tokenizer = new StringTokenizer(s, "{:},", true); | |
if (tokenizer.hasMoreTokens()) { | |
return parseValue(tokenizer, tokenizer.nextToken()); | |
} | |
else { | |
return null; | |
} | |
} | |
private enum ObjectParseState { | |
PARSE_KEY, | |
PARSE_COLON, | |
PARSE_VALUE, | |
PARSE_COMMA | |
} | |
public static void main(String[] args) { | |
System.out.println(new JsonParser().parse( | |
"{ \"group name\" : \"development\",\n" + | |
" \"members\": [\n" + | |
" {\n" + | |
" \"name\":\"Alice\",\n" + | |
" \"age\":42,\n" + | |
" \"language\":\"Zig\"\n" + | |
" }, {\n" + | |
" \"name\" : \"Bob\" , \"age\" : 16 ,\n" + | |
" \"language\" : \"Perl\" ,\n" + | |
" \"pi\" : 3.14\n" + | |
" }\n" + | |
" ]\n" + | |
"}" | |
)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment