본문으로 건너뛰기
jsonbeautifiers
한국어

JSON 파서

페이로드를 파싱해 타입, 깊이, 키 개수, 모든 경로를 확인합니다.

입력

붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기

파싱은 텍스트를 구조로 바꿉니다. 이 페이지는 그 결과로 무엇이 나왔는지 보여 줍니다. 타입, 중첩 깊이, 키와 배열의 개수, JavaScript 파서에서 살아남지 못할 숫자, 그리고 중복 키의 위치.

페이로드를 건네받고 나서 "여기에 실제로 뭐가 들어 있지"가 첫 질문일 때 여는 페이지입니다.

통계가 알려 주는 것

하나하나가 문서를 상대로 코드를 쓰기 직전에 떠오르는 질문에 답합니다.

최대 깊이
중첩이 얼마나 깊은지. 수백 단계를 넘어가면 받아 쓰는 쪽이 어떻게 동작하는지 확인하세요. 여기서 측정한 결과 V8은 백만 단계까지 파싱하지만 약 4,800단계보다 깊으면 직렬화를 거부하고, CPython의 C 스캐너는 파이썬 재귀 한도가 1,000인데도 약 17,000단계까지 처리합니다.
키 개수와 객체 개수
매퍼나 ORM이 할 일의 양, 그리고 트리가 메모리에서 차지할 크기를 대략 가늠하는 지표입니다.
안전하지 않은 숫자
2^53-1을 넘는 정수가 몇 개인지. 이 값이 0이 아니라면 JavaScript 쪽 소비자는 이미 파일과 다른 값을 읽고 있습니다.
중복 키
두 번 정의된 객체 키가 몇 개인지, 그리고 각각의 위치.

파싱은 형태 검증과 다릅니다

문서가 완벽하게 파싱되고도 여러분에게 쓸모없을 수 있습니다. 필드 이름이 바뀌었거나, 숫자가 문자열로 왔거나, 객체를 기대한 자리에 배열이 있거나. 파싱은 문법을 확인할 뿐 계약을 확인하지 않습니다.

계약을 확인하려면 믿을 만한 페이로드에서 JSON Schema를 생성하고, 이후의 페이로드를 그것에 대해 검증하세요.

이 파서가 JSON.parse와 다른 점

재귀가 아니라 반복으로 동작하므로 중첩 깊이는 메모리만이 한계입니다. 모든 숫자의 원본 소스 텍스트를 기록하므로 조용히 반올림되는 일이 없습니다. 모든 토큰의 위치를 추적하므로 오류에 행과 열이 붙습니다. 그리고 오류가 나도 멈추지 않고 복구하므로, 깨진 문서도 한 번에 모든 문제를 보고합니다.

그 대가는 속도입니다. 여기서는 초당 약 12~16MB로, 네이티브 JSON.parse의 60~70MB에 못 미칩니다. 그게 정보를 얻는 값이고, 이 작업을 백그라운드 워커에서 돌리는 이유이기도 합니다.

How to do this in code

코드에서 파싱하는 방법, 그리고 보통 너무 늦게 알게 되는 옵션들입니다.

js JavaScript

reviver로는 원래 자릿수를 되살릴 수 없습니다. reviver가 실행될 때쯤이면 숫자는 이미 부동소수점으로 바뀐 뒤입니다.

const value = JSON.parse(text);

// The reviver runs on every key and value, which is how you
// intercept large integers before precision is lost.
const value2 = JSON.parse(text, function (key, val) {
  if (typeof val === 'number' && !Number.isSafeInteger(val)) {
    // this[key] is the raw value; the original TEXT is not
    // available here, which is the limitation.
    console.warn('unsafe integer at', key);
  }
  return val;
});
py Python

파이썬에서 중복 키를 감지하는 이식 가능한 방법은 object_pairs_hook뿐입니다.

import json
from decimal import Decimal

# parse_float and parse_int receive the raw TEXT of the number,
# so unlike JavaScript you can keep full precision.
data = json.loads(text, parse_float=Decimal, parse_int=int)

# Detect duplicate keys instead of silently keeping the last
def no_dupes(pairs):
    seen = {}
    for k, v in pairs:
        if k in seen:
            raise ValueError(f'duplicate key: {k}')
        seen[k] = v
    return seen

data = json.loads(text, object_pairs_hook=no_dupes)
go Go
// UseNumber keeps the original text instead of converting
// to float64, so large integers survive.
dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()

var v any
if err := dec.Decode(&v); err != nil {
    return err
}
java Java
ObjectMapper mapper = new ObjectMapper();

// Fail loudly on duplicates rather than keeping the last one
mapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);

// Keep big integers exact
mapper.enable(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS);

자주 묻는 질문

파싱했더니 숫자가 달라졌습니다. 왜인가요?
JSON 숫자에는 크기 제한이 없고 IEEE 754 double에는 있기 때문입니다. 2^53-1을 넘는 정수와 많은 소수는 정확히 표현할 수 없습니다. Python, Go, Java는 모두 원본 텍스트를 유지할 방법을 제공하지만 JavaScript는 아닙니다. 큰 ID를 문자열로 보내야 하는 이유가 여기 있습니다.
중복 키는 어떻게 되나요?
RFC 8259는 정의하지 않습니다. JavaScript와 Python은 마지막 것을 남기고, 일부 Go와 Java 설정은 문서를 거부하며, 일부 파서는 첫 번째를 남깁니다. 절대 여기에 기대지 마세요. 이 페이지는 모든 중복을 두 위치와 함께 보고합니다.