Last active
February 18, 2018 04:07
-
-
Save rendon/c1639842844ef4439944c314bd7684b7 to your computer and use it in GitHub Desktop.
Basic JSON parser (super incomplete)
This file contains hidden or 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
package mx.letmethink; | |
import java.util.HashMap; | |
import java.util.Map; | |
public class Main { | |
public static void main(String[] args) { | |
String text = "{}"; | |
// System.out.println(new JsonParser(text).parse()); | |
// System.out.println(new JsonParser("{\"key\": \"value\", \"num\": 1234}").parse()); | |
System.out.println(new JsonParser("{\"key\":{\"a\":{\"b\":\"{12345}678\"}}}").parse()); | |
} | |
} | |
class JsonParser { | |
private static final char CLOSING_BRACE = '}'; | |
private static final char COMMA = ','; | |
private final char[] chars; | |
int position; | |
private static final JsonException UNEXPECTED_END_OF_TEXT = new JsonException("Unexpected end of text"); | |
public JsonParser(String text) { | |
this.chars = text.toCharArray(); | |
} | |
public JsonObject parse() { | |
return readObject(); | |
} | |
public JsonObject readObject() { | |
JsonObject object = new JsonObject(); | |
readOpeningBrace(); | |
while (true) { | |
if (peek() == CLOSING_BRACE) { | |
break; | |
} | |
String key = readKey(); | |
readColon(); | |
if (Character.isDigit(peek())) { | |
JsonNumber jsonNumber = readNumber(); | |
object.put(key, jsonNumber); | |
} else if (peek() == '"') { | |
object.put(key, readString()); | |
} else { | |
object.put(key, readObject()); | |
} | |
if (peek() == CLOSING_BRACE) { | |
break; | |
} | |
readComma(); | |
} | |
readClosingBrace(); | |
return object; | |
} | |
private JsonNumber readNumber() { | |
strip(); | |
long value = 0; | |
while (position < chars.length && Character.isDigit(chars[position])) { | |
value = value * 10 + chars[position++] - '0'; | |
} | |
if (position == chars.length) { | |
throw UNEXPECTED_END_OF_TEXT; | |
} | |
return new JsonNumber(value); | |
} | |
private JsonString readString() { | |
strip(); | |
if (chars[position] != '"') { | |
throw new JsonException("Expected opening '\"'"); | |
} | |
position++; | |
String value = ""; | |
while (position < chars.length && chars[position] != '"') { | |
value += chars[position++]; | |
} | |
if (position == chars.length) { | |
throw UNEXPECTED_END_OF_TEXT; | |
} | |
if (chars[position] != '"') { | |
throw new JsonException("Expected closing '\"'"); | |
} | |
position++; | |
return new JsonString(value); | |
} | |
private void readOpeningBrace() { | |
strip(); | |
if (chars[position] != '{') { | |
throw new JsonException("Expected '{', found " + chars[position]); | |
} | |
position++; | |
} | |
private void readClosingBrace() { | |
strip(); | |
if (chars[position] != CLOSING_BRACE) { | |
throw new JsonException("Expected '}'"); | |
} | |
position++; | |
} | |
private char peek() { | |
strip(); | |
return chars[position]; | |
} | |
private String readKey() { | |
strip(); | |
if (chars[position] != '"') { | |
throw new JsonException("Expected opening \""); | |
} | |
position++; | |
String key = ""; | |
while (position < chars.length && chars[position] != '"') { | |
key += chars[position++]; | |
} | |
if (position == chars.length) { | |
throw UNEXPECTED_END_OF_TEXT; | |
} | |
if (chars[position] != '"') { | |
throw new JsonException("Expected closing \""); | |
} | |
position++; | |
return key; | |
} | |
private void readColon() { | |
strip(); | |
if (chars[position] != ':') { | |
throw new JsonException("Expected ':'"); | |
} | |
position++; | |
} | |
private void readComma() { | |
strip(); | |
if (chars[position] != COMMA) { | |
throw new JsonException("Expected ','"); | |
} | |
position++; | |
} | |
private void strip() { | |
while (position < chars.length && chars[position] == ' ') { | |
position++; | |
} | |
if (position == chars.length) { | |
throw UNEXPECTED_END_OF_TEXT; | |
} | |
} | |
} | |
class JsonObject { | |
private Map<String, JsonObject> map; | |
public JsonObject() { | |
map = new HashMap<>(); | |
} | |
public void put(String key, JsonObject object) { | |
map.put(key, object); | |
} | |
@Override | |
public String toString() { | |
return toString(""); | |
} | |
public String toString(String indent) { | |
String str = "{\n"; | |
int totalEntries = map.entrySet().size(); | |
int count = 0; | |
for (Map.Entry<String, JsonObject> entry : map.entrySet()) { | |
str += indent + " " + "\"" + entry.getKey() + "\": " + entry.getValue().toString(indent + " "); | |
count++; | |
if (count < totalEntries) { | |
str += ", "; | |
} | |
} | |
str += "\n" + indent + "}"; | |
return str; | |
} | |
} | |
class JsonNumber extends JsonObject { | |
private final long value; | |
public JsonNumber(long value) { | |
this.value = value; | |
} | |
public String toString(String indent) { | |
return toString(); | |
} | |
@Override | |
public String toString() { | |
return value + ""; | |
} | |
} | |
class JsonString extends JsonObject { | |
private final String value; | |
public JsonString(String value) { | |
this.value = value; | |
} | |
public String toString(String indent) { | |
return toString(); | |
} | |
@Override | |
public String toString() { | |
return "\"" + value.replace("\"", "\\") + "\""; | |
} | |
} | |
class JsonException extends RuntimeException { | |
public JsonException(String message) { | |
super(message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment