JSON 형태의 문자열 입력을 파싱해서 유효한 형태인지 출력합니다.
단 지원하는 json decoding 함수나 라이브러리는 사용하지 않습니다.
Sample Input
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}
[12, 23, 34, "23"]
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}
["level":3, 23, 34, "23"]
Sample Output
Valid JSON
Valid JSON
Parse error!
Parse error!
11개의 풀이가 있습니다.
출제자의 의도와는 전혀 다르게 반칙성으로 풀었습니다. 풀이는 사실 한줄입니다. 파이썬의 eval
data = '''
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}
[12, 23, 34, "23"]
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}
["level":3, 23, 34, "23"]
'''
def is_valid_json(s):
try:
eval(s)
return True
except:
return False
for line in data.split("\n"):
line = line.strip()
if not line: continue
print is_valid_json(line)
C#으로 작성했습니다.
public bool ValidateJson(string input)
{
try
{
JObject.Parse(input);
return true;
}
catch (Exception)
{
return false;
}
}
정규식을 이용하면 좋을 것 같은데...공부중인 lisp으로! 문제 해결보다는 언어 적응이 우선이네요ㅠ;
(defun is-valid-json-p (text)
(let*
(
(characters (coerce text 'list))
(first-letter (car characters))
)
(cond
((eq first-letter #\{) (parse-dictionary (cdr characters)))
((eq first-letter #\[) (parse-array (cdr characters)))
(t nil)
)
)
)
(defun parse-object (characters)
(let*
(
(data (copy-list characters))
(first (car data))
)
(setf data
(cond
((eq first #\") (parse-string (cdr data)))
((eq first #\[) (parse-array (cdr data)))
((eq first #\{) (parse-dictionary (cdr data)))
((eq first #\ ) (parse-object (cdr data)))
((digit-char-p first) (parse-digit (cdr data)))
((alpha-char-p first) (parse-alpha (cdr data)))
(t nil)
)
)
)
)
(defun parse-dictionary (characters)
(let*
(
(data (copy-list characters))
(parsed nil)
)
(loop do
(let ((first (car data)))
(setf data
(cond
((eq first #\") (parse-string (cdr data)))
((eq first #\:) (parse-object (cdr data)))
((eq first #\[) (parse-array (cdr data)))
((eq first #\{) (parse-dictionary (cdr data)))
((eq first #\}) (setf parsed t) (cdr data))
((eq first #\ ) (cdr data))
((eq first #\,) (parse-object (cdr data)))
((digit-char-p first) (parse-digit (cdr data)))
((alpha-char-p first) (parse-alpha (cdr data)))
(t nil)
)
)
)
when (or
(zerop (length data))
(not (null parsed))
)
return (values data parsed)
)
)
)
(defun parse-array (characters)
(let*
(
(data (copy-list characters))
(parsed nil)
)
(loop do
(let ((first (car data)))
(setf data
(cond
((eq first #\") (parse-string (cdr data)))
((eq first #\[) (parse-array (cdr data)))
((eq first #\]) (setf parsed t) (cdr data))
((eq first #\{) (parse-dictionary (cdr data)))
((eq first #\ ) (cdr data))
((eq first #\,) (parse-object (cdr data)))
((digit-char-p first) (parse-digit (cdr data)))
((alpha-char-p first) (parse-alpha (cdr data)))
(t nil)
)
)
)
when (or
(zerop (length data))
(not (null parsed))
)
return (values data parsed)
)
)
)
(defun parse-string (characters)
(if (zerop (length characters))
nil
(let ((first (car characters)))
(if (eq first #\")
(cdr characters)
(parse-string (cdr characters))
)
)
)
)
(defun parse-digit (characters)
(if (zerop (length characters))
nil
(let ((first (car characters)))
(if (digit-char-p first)
(parse-digit (cdr characters))
characters
)
)
)
)
(defun parse-alpha (characters)
(if (zerop (length characters))
nil
(let ((first (car characters)))
(if (alpha-char-p first)
(parse-alpha (cdr characters))
characters
)
)
)
)
;; test
(defconstant json1 "{\"level\":3, \"attr\":{\"power\":120, \"name\":\"hero\"}, \"friendIds\":[12, 23, 34, 23]}")
(defconstant json2 "[12, 23, 34, \"23\"]")
(defconstant json3 "{\"level\":3, \"attr\":{\"power\":120, \"name\":\"hero\"}, \"friendIds\":[12, 23, 34, 23}")
(defconstant json4 "[\"level\":3, 23, 34, \"23\"]")
(defconstant json5 "{\"ID\":null,\"name\":\"Doe\",\"first-name\":\"John\",\"age\":25,\"hobbies\":[\"reading\",\"cinema\",{\"sports\":[\"volley-ball\",\"snowboard\"]}],\"address\":{}}")
(defconstant json6 "{\"card\":\"2\",\"numbers\":{\"Conway\":[1,11,21,1211,111221,312211],\"Fibonacci\":[0,1,1,2,3,5,8,13,21,34]}}")
(defconstant json7 "{\"ID\"::null,\"name\":\"Doe\",\"first-name\":\"John\",\"age\":25,\"hobbies\":[\"reading\",\"cinema\",{\"sports\":[\"volley-ball\",\"snowboard\"]}],\"address\":{}}")
(defconstant json8 "{\"card\":\"2\",,\"numbers\":{\"Conway\":[1,,11,21,1211,111221,312211],\"Fibonacci\":[0,1,1,2,3,5,8,13,21,34]}}")
(is-valid-json-p json1)
(is-valid-json-p json2)
(is-valid-json-p json3)
(is-valid-json-p json4)
(is-valid-json-p json5)
(is-valid-json-p json6)
(is-valid-json-p json7)
(is-valid-json-p json8)
JSON 형식에 대해 살펴보면 루트가 {키: 값} 혹은 {키:값, 키:값...} 이거나 [값, 값, ... ] 의 형태입니다.
이 때 키는 문자열 형식만 가능하고 값은 배열, 객체, 숫자, 문자열이 올 수 있습니다.
하는 김에 정규식을 쓰지 않고 무식하게 한글자씩 스캔해서 파싱하는 형태로 구현했습니다.
data = """{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds": [12, 23, 34, 23]}
[12, 23, 34, "23"]
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}
["level":3, 23, 34, "23"]""".split('\n')
class JSONError(Exception):
pass
def skip_space(s, i):
while s[i] in ' \s\n\t\r':
i += 1
return (s, i)
def parse_root(s):
s = s.strip()
i = 0
try:
if s[i] == '{':
_, _, r = parse_object(s, i)
elif s[i] == '[':
_, _, r = parse_array(s, i)
else:
raise JSONError("잘못된 루트 객체 --> %d" % i)
print("Valid JSON")
return r
except JSONError:
print("parse error!")
def parse_object(s, i):
"""시작이 '{'인 경우 객체를 파싱한다."""
i += 1
a, l = i, len(s)
result = dict()
while s[i] != '}':
key, value = "", None
_, i = skip_space(s, i)
_, i, key = parse_string(s, i)
if not key:
raise JSONError("비어있는 키 값 발견")
_, i = skip_space(s, i)
if s[i] != ':':
raise JSONError("키 뒤에 :이 아님 --> %d" % i)
else:
i += 1
_, i = skip_space(s, i)
if s[i] == '{':
_, i, value = parse_object(s, i)
elif s[i] == '[':
_, i, value = parse_array(s, i)
elif s[i] == '"':
_, i, value = parse_string(s, i)
elif s[i] in '+-.0123456789':
_, i, value = parse_number(s, i)
_, i = skip_space(s, i)
if s[i] == ',':
if value is None:
raise JSONError("값 없이 ,가 나옴 --> %d" % i)
else:
i += 1
result[key] = value
_, i = skip_space(s, i)
if i >= l:
raise JSONError("비정상적인 문자열 끝 --> %d"% i)
i += 1
return s, i, result
def parse_array(s, i):
"""시작이 '[' 인 경우 배열형태로 파싱한다."""
i += 1
a, l = i, len(s)
result = []
while s[i] != ']':
k = None
_, i = skip_space(s, i)
if s[i] in "+-.0123456789":
_, i, k = parse_number(s, i)
result.append(k)
elif s[i] == '"':
_, i, k = parse_string(s, i)
result.append(k)
elif s[i] == '[':
_, i, k = parse_array(s, i)
result.append(k)
elif s[i] == '{':
_, i, k = parse_object(s, i)
result.append(k)
else:
raise JSONError("올바르지 않은 토큰 --> %d" % i)
_, i = skip_space(s, i)
if s[i] == ',':
if k is None:
raise JSONError("요소 없이 ,가 나옴 --> %d" % i)
i += 1
if i >= l:
raise JSONError("배열이 닫히지 못함 --> %d" % i)
_, i = skip_space(s, i)
i += 1
return s, i, result
def parse_string(s, i):
a, l = i, len(s)
i += 1
while s[i] != '"':
i += 1
if i >= l:
raise JSONError("문자열이 닫히지 못함 --> %d" % i)
i += 1
return (s, i, s[a+1:i-1])
def parse_number(s, i):
has_point = False
has_sign = False
a = i
l = len(s)
while s[i] in "+-0123456789.":
if s[i] in "+-":
if has_sign:
raise JSONError("유효하지 않은 숫자 --> %d" % i)
has_sign = True
i += 1
elif s[i] in '0123456789':
i += 1
elif s[i] == '.':
if has_point:
raise JSONError("유효하지 않은 실수 --> %d" % i)
has_point = True
i += 1
else:
raise JSONError("파싱할 수 없는 숫자값 --> %d" % i)
if i >= l:
raise JSONError("비정상적인 문자열 끝 --> %d" % i)
if a == i:
raise JSONError("유효한 숫자값을 추출하지 못함 --> %d" % i)
return (s, i, float(s[a:i]) if has_point else int(s[a:i]))
Ruby
Hash(키가 Symbol인 것), Array로 파싱되는 것은 true. 그 밖의 것들은 parse error.
def is_valid_json(str)
eval_exp = eval(str)
(eval_exp.class == Hash && eval_exp.keys.all? {|e| e.class == Symbol} ) ||
(eval_exp.class == Array) ? "true" : Exception
rescue Exception; "Parse error!"
end
Test
# json_lib 크로스 체크
require 'json'
def chk_with_jsonlib(str)
JSON.parse(str) ? "true" : Exception
rescue Exception; "Parse error!"
end
# test data
valids = ['{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}', '[12, 23, 34, "23"]']
not_valids = ['{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}', '["level":3, 23, 34, "23"]']
hash_but_json_err = '{"key" => value}' # 해쉬지만 json이 아닌 것.
all_cases = valids + not_valids + [hash_but_json_err]
# test
expect( valids.map {|s| is_valid_json(s) } ).to eq ["true"]*2
expect( not_valids.map {|s| is_valid_json(s) } ).to eq ["Parse error!"]*2
expect( is_valid_json(hash_but_json_err) ).to eq "Parse error!"
# json_lib로 파싱한 결과와 크로스 체크
expect( all_cases.map {|s| is_valid_json(s) } ).to eq all_cases.map {|s| chk_with_jsonlib(s) }
import re
key_ = re.compile(r'(_s_|_n_|_e_|_oa_)')
string_ = re.compile(r'((?<!\\)([\'"])[^\n]*?(?<!\\)\2)')
number_ = re.compile(r'(0x[a-fA-F0-9]+|0o[1-7]+|([+\-]?([0-9]+|[0-9]*(?=\.))(\.[0-9]*)?([eE][+\-]?[0-9]+)?))')
etc_ = re.compile(r'(True|False|None)')
object_array_ = re.compile(r'(\{(_s_|_n_):(_s_|_n_|_e_|_oa_)(,(_s_|_n_):(_s_|_n_|_e_|_oa_))*\})|(\[(_s_|_n_|_e_|_oa_)(,(_s_|_n_|_e_|_oa_))*\])')
def json_validator(json_):
json_ = re.sub(key_, "_x_", json_)
json_ = re.sub(string_, "_s_", json_)
json_ = re.sub(number_, "_n_", json_)
json_ = re.sub(etc_, "_e_", json_)
json_ = re.sub(r'\s+', '', json_)
while len(re.findall(object_array_, json_)) != 0:
json_ = re.sub(object_array_, "_oa_", json_)
print('Valid JSON' if json_ == '_oa_' else 'Parse error!')
json_validator('{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}')
json_validator('[12, 23, 34, "23"]')
json_validator('{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}')
json_validator('["level":3, 23, 34, "23"]')
Python 3.5.2에서 작성하였습니다.
JavaScript
function isspace(c) {
return " \t\r\n".indexOf(c) !== -1;
}
function isdigit(c) {
return "0123456789".indexOf(c) !== -1;
}
function validate(s) {
let i = 0;
function match(token) {
space();
if (!s.substring(i).startsWith(token)) error("Expected: " + token);
i += token.length;
}
function error(message) {
throw new Error(message + s.substring(i));
}
function regex(re) {
var result = re.exec(s.substring(i));
if (!result) error("Expected: " + re);
i += result[0].length;
}
function str() {
space();
regex(/^"(\\("|\\|[bfnrt]|u[0-9a-hA-H]{4})|[^\\"])*"/);
}
function num() {
space();
regex(/^-?(\d|[1-9]\d+)(\.\d+)?((e|E)(\+|-)?\d+)?\b/);
}
function member() {
str();
match(":");
json();
}
function obj() {
match("{");
listOf(member, "}");
}
function arr() {
match("[");
listOf(json, "]");
}
function listOf(p, closer) {
space();
while (s[i] !== closer) {
p();
space();
if (s[i] === ",") {
i++;
} else if (s[i] !== closer) {
error("Expected , or" + closer);
}
}
i++;
}
function space() {
while (isspace(s[i])) i++;
}
function json() {
space();
if (s[i] === "{") {
obj();
} else if (s[i] === "[") {
arr();
} else if (s[i] === "\"") {
str();
} else if (s[i] == "-" || isdigit(s[i])) {
num();
} else {
regex(/^(true|false|null)\b/);
}
}
try {
json();
space();
return i == s.length;
} catch (e) {
return false;
}
}
let o = {
x: 23,
y: [true, false, null, -1e100, {}]
}
console.log(validate(" " + JSON.stringify(o)+" "));
def chk_string(S):
s_sw, n_sw, switch = 0,0,0
colon_switch = 0
for x in S:
if x == '"':
switch = not switch
elif x == ':':
colon_switch = not colon_switch
if x.isalpha() and not switch:
return False
switch = 0
for x in S:
if x.isnumeric() and not switch:
n_sw = 1
elif x == '"' or x == '{' or x == '[':
s_sw = 1
switch = not switch
elif x == ',' or x == ':':
s_sw, n_sw = 0,0
if n_sw == 1 and s_sw == 1:
return False
return True
def test_list(S):
S = S.split(',')
switch = 0
for x in S:
for y in x:
if y == '"' or y == '{' or y == '}':
switch = not switch
elif y == ':' and not switch:
return False
return True
def test_main(S):
tmp = list()
colon_count, p_count = 0,0
start, end, switch = 0,0,0
a,b = 0, 0
for x in range(len(S)):
if S[x] == '{' or S[x] == '[':
p_count += 1
if p_count == 1:
start, switch = x, not switch
if S[x] == '}' or S[x] == ']':
p_count -= 1
if p_count == 0:
end, switch = x+1, not switch
if not json_test(S[start:end]):
return False
if S[x] == ',' and not switch:
b = x+1
tmp.append(S[a:b])
a = b
elif S[x] == ':' and not switch:
colon_count += 1
tmp.append(S[a:])
if colon_count == len(tmp) and not switch:
return True
else:
return False
def json_test(S):
S = S.replace(' ','')
if S[0] == '{' and S[-1] == '}' and chk_string(S):
return test_main(S[1:len(S)-1])
elif S[0] == '[' and S[-1] == ']' and chk_string(S):
return test_list(S[1:len(S)-1])
else:
return False
_list = ['{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}',
'[12, 23, 34, "23"]',
'{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}',
'["level":3, 23, 34, "23"]',
'{"level":3, "attr":{"power":[{"power":120},12, 23, 34, 23]}, "friendIds":[{"power":120},[12, 23], 34, 23]}',
'{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}'
]
for S in _list:
if json_test(S):
print('Valid JSON')
else:
print('Parse error!')
#### 2017.01.16 D-401 ####
허얽허얽.. 포기했다가 성에 안차서 다시 머리싸매고 풀었는데 뭔가 노답입니다... 그래도.. 해냈다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool valid(char* s, int size, int type);
int middle(char json[], int start);
int small(char json[], int start);
int size;
bool v = true;
void main() {
char json[] = "{\"level\":3, \"attr\":{\"power\":120, \"name\":\"hero\"}, \"friendIds\":[12, 23, 34, 23]}";
//char json[] = "[12, 23, 34, \"23\"]";
//char json[] = "{\"level\":3, \"attr\":{\"power\":120, \"name\":\"hero\"}, \"friendIds\":[12, 23, 34, 23}";
//char json[] = "[\"level\":3, 23, 34, \"23\"]";
size = strlen(json);
int h=0, m=0;
for(int i=0;i<size;i++) {
if(json[i] == '{') {
i=middle(json, i);
}
if(json[i] == '[') {
i=small(json, i);
}
}
for(int i=0;i<size;i++) {
if(json[i] == '{') m++;
else if(json[i] == '[') h++;
else if(json[i] == '}') m--;
else if(json[i] == ']') h--;
}
if(h!=0 || m!=0)
v = false;
if(v==false)
printf("Pasrse Error");
else
printf("Valid Json");
}
int middle(char json[], int start) {
int i=start;
while(json[i] != '}' && i<size) {
i++;
if(json[i] == ' ') {
i++;
}
int index = i;
char* temp;
while(json[i]!=',' && json[i] != '}') {
if(json[i] == '[') {
i = small(json, i);
}
if(json[i] == '{' ) {
i = middle(json, i);
}
i++;
}
temp = (char*) malloc (sizeof(char) * (i-index));
memmove(temp, json+index, sizeof(char) * i-index);
temp[i-index] = '\0';
v = valid(temp, i-index, 0);
}
return i;
}
int small(char json[], int start) {
int i=start;
while(json[i] != ']' && i<size) {
i++;
if(json[i] == ' ') {
i++;
}
int index = i;
char* temp;
while(json[i]!=',' && json[i] != ']') {
if(json[i] == '[') {
i = middle(json, i);
}
i++;
}
temp = (char*) malloc (sizeof(char) * (i-index));
memmove(temp, json+index, sizeof(char) * i-index);
v = valid(temp, i-index, 1);
}
return i;
}
bool valid(char* s, int size, int type) {
if(type == 0) {
int c=0;
for(int i=0;i<size;i++) {
if(s[0]!='\"')
return false;
if(i!=0 && s[i]=='\"') {
c++;
if(c==1 && s[i+1]!=':')
return false;
}
}
}
else {
int c=0;
for(int i=0;i<size;i++) {
if(s[i]=='\"') {
c++;
}
if(s[i]==':')
return false;
// 65 ~ 90 97 ~ 122 48 ~ 57
}
if(c>2 || c==1)
return false;
}
if(v==true)
return true;
else
return false;
}
class str_consumer:
def __init__(self, s):
self.s = s
def exhausted(self):
return not self.s.strip()
def consume(self, chars):
tmp = self.s.lstrip()
if tmp and tmp[0] in chars:
self.s = tmp[1:]
return True
else:
return False
def consume_while(self, chars):
while self.s and self.s[0] in chars:
self.s = self.s[1:]
return True
def consume_until(self, char):
i = self.s.find(char)
if i >= 0:
self.s = self.s[i+1:]
return True
else:
return False
# 소수, "\"", [], {}는 처리 안 함
def json(s): return (jarray(s) or jobject(s)) and s.exhausted()
def primitive(s): return jint(s) or jstr(s) or jobject(s) or jarray(s)
def jint(s): return s.consume('0123456789') and s.consume_while('0123456789')
def jstr(s): return s.consume('"') and s.consume_until('"')
def jarray(s): return s.consume('[') and arrlist(s)
def arrlist(s): return primitive(s) and (s.consume(']') or s.consume(',') and arrlist(s))
def kvpair(s): return jstr(s) and s.consume(':') and primitive(s)
def jobject(s): return s.consume('{') and kvlist(s)
def kvlist(s): return kvpair(s) and (s.consume('}') or s.consume(',') and kvlist(s))
data = '''{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}\n[12, 23, 34, "23"]\n{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}\n["level":3, 23, 34, "23"]'''
for line in data.split('\n'):
print(json(str_consumer(line)))
특정 타입(예: jarray)의 함수를 호출하면 "유효한 jarray인지"를 리턴하고,
유효할 경우에만 s의 첫 번째 문자부터 차례로 consume합니다.
consume함수들은 문자가 매치됐을 경우 다음 문자로 진행하는 일과, 검사 결과를 참/거짓으로 리턴하는 두 가지 일을 합니다.
위 코드는 대부분 잘 작동하지만 사실 몇몇 경우에 false-positive가 나오는데,
정확히 하려면 아래와 같이 각 함수마다 실패했을 때 롤백하는 코드를 넣어줘야 합니다.
되돌리는 방법이야 여러 가지 있겠는데 전체적으로 좀 지저분해져서 빼놨습니다.
def arrlist(s):
ss = s.clone() # clone()함수 만들었다 치고..
if primitive(s) and ss.consume(']'):
return True
s = ss
if primitive(s) and s.consume(',') and arrlist(s):
return True
s = ss
return False
def json_validator(v):
v = v.strip()
end = 0
if v[:1] == '{' and v[-1:] == '}':
if v[1:-1].strip() == '': return True
idx = 1
while True:
beg = end+1
if idx&1:
while True:
end = v.find(':', end+1)
if end == -1: return False
if json_isstring(v[beg:end]): break
else:
while True:
end = v.find(',', end+1)
if end == -1: return json_validator(v[beg:end])
if json_validator(v[beg:end]): break
idx += 1
elif v[:1] == '[' and v[-1:] == ']':
if v[1:-1].strip() == '': return True
while True:
beg = end+1
while True:
end = v.find(',', end+1)
if end == -1: return json_validator(v[beg:end])
if json_validator(v[beg:end]): break
else:
return json_isnumber(v) or json_isstring(v) or json_isboolean(v) or json_isnull(v)
def json_isnumber(v):
return v.strip().lstrip('-').replace('.','',1).isdigit()
def json_isstring(v):
v = v.strip()
cnt = v.count('"')
if cnt < 2: return False
elif cnt == 2: return v[0]+v[-1] == '""'
else: return v.count('\\"')+2 == cnt
def json_isboolean(v):
v = v.strip()
return v == 'true' or v == 'false'
def json_isnull(v):
return v.strip() == 'null'
test = '''\
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}
[12, 23, 34, "23"]
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}
["level":3, 23, 34, "23"]
{ }
[]
{"sample\\\"test\\\"": "x", "[test}": [134], "-PI": -3.14159265}'''
for i in test.splitlines(): print(i,'\nValid JSON\n' if json_validator(i) else '\nParse error!\n')
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23]}
Valid JSON
[12, 23, 34, "23"]
Valid JSON
{"level":3, "attr":{"power":120, "name":"hero"}, "friendIds":[12, 23, 34, 23}
Parse error!
["level":3, 23, 34, "23"]
Parse error!
{ }
Valid JSON
[]
Valid JSON
{"sample\"test\"": "x", "[test}": [134], "-PI": -3.14159265}
Valid JSON