이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

JSON Validator

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!
JSON decode

2015/02/02 10:44

vegan

https://ko.wikipedia.org/wiki/JSON - Noname, 2017/08/28 06:13

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)

2015/02/06 16:20

pahkey

C#으로 작성했습니다.

        public bool ValidateJson(string input)
        {
            try
            {
                JObject.Parse(input);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

2016/06/02 15:57

Straß Böhm Jäger

정규식을 이용하면 좋을 것 같은데...공부중인 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)

2015/06/06 08:17

꽃샘더위

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]))

2016/05/03 15:56

룰루랄라

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) }

2016/07/24 08:31

rk

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에서 작성하였습니다.

2016/11/28 16:49

Yeo HyungGoo

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)+"  ")); 



2016/12/06 01:19

Han Jooyung

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 ####

허얽허얽.. 포기했다가 성에 안차서 다시 머리싸매고 풀었는데 뭔가 노답입니다... 그래도.. 해냈다.

2017/01/17 22:32

GunBang

#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;
}

2017/03/02 16:46

코딩초보

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

2017/08/28 14:01

Noname

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

2018/09/01 05:52

Creator

목록으로