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

JSON 포맷터

공백 2칸, 4칸, 탭으로 JSON을 정렬하면서 숫자는 한 자리도 바꾸지 않습니다.

JSONPath로 필터링

RFC 9535 문법입니다. 결과는 이 창을 연 패널을 대체합니다.

 

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

JSON을 정렬한다는 것은 사람에게는 필요하지만 기계에는 필요 없는 공백을 넣는 일입니다. 한 줄에 멤버 하나, 일관된 들여쓰기, 콜론 뒤의 공백 하나. 데이터는 바뀌지 않습니다. 바뀌는 것은 보이는 방식뿐입니다.

그런데 바로 그 마지막 문장이 틀어지기 쉬운 지점입니다. 문서를 JavaScript 값으로 파싱했다가 다시 문자열로 만드는 도구는 무언가를 출력하기도 전에 이미 여러분의 숫자를 바꿔 놓았고, 대부분의 도구가 정확히 그렇게 동작합니다.

정렬이 바꾸지 않는 것

이 도구는 파싱된 값을 다시 직렬화하는 대신, 읽어 들인 토큰을 그대로 다시 내보냅니다. 즉 모든 숫자, 문자열, 리터럴의 텍스트가 바이트 단위로 그대로 돌아오고, 다시 쓰이는 것은 그 사이의 공백뿐입니다.

들리는 것보다 훨씬 중요한 이야기입니다. 19자리 ID가 들어 있는 문서를 JSON.parse와 JSON.stringify 위에 만든 도구에 통과시키면, ID는 조용히 다른 값이 되어 돌아옵니다. 화면 어디에도 경고는 없습니다.

숫자는 원래 텍스트 그대로
1.50은 1.50으로, 1e3은 1e3으로, -0은 -0으로 남고, 12345678901234567890은 12345678901234567000이 되지 않고 그대로 남습니다.
문자열은 글자 그대로 복사
이스케이프된 \u00e9는 이스케이프된 채로, 리터럴 é는 리터럴 그대로 남습니다. 문자열을 어떻게 인코딩할지 정하는 것은 정렬의 일이 아니므로, 정하지 않습니다.
키 순서는 유지
정렬을 명시적으로 켜지 않는 한 유지됩니다. 명세상 JSON 객체는 순서가 없지만, 실제로는 모든 파서가 삽입 순서를 유지하며 diff는 여기에 의존합니다.
중복 키는 남기고 표시
하나를 지우면 이 문서를 소비하는 쪽이 보는 내용이 달라집니다. 대신 두 위치를 모두 알려 주는 경고를 받게 됩니다.

어떤 들여쓰기를 고를까

여기서 기본값이 공백 2칸인 이유는 npm, Prettier를 비롯한 대부분의 JavaScript 도구가 그렇게 출력하기 때문이고, JSON의 중첩이 금세 깊어지기 때문입니다. 중첩이 얕은 설정 파일은 공백 4칸이 더 읽기 좋습니다. 탭은 읽는 사람이 각자 너비를 고를 수 있어 접근성 면에서 유리하고, 압축률도 아주 조금 더 좋습니다.

읽히는 것이 아니라 전송되는 데이터라면 정렬 대신 압축하세요. JSON 응답 속 공백은 순수한 오버헤드이고, 일반적인 API 페이로드에서는 전체 바이트의 10~20퍼센트를 차지합니다.

줄바꿈 문자와 끝줄 개행

출력은 기본적으로 LF를 사용합니다. CRLF 옵션이 있는 이유는 Windows 도구와 일부 CI 시스템이 이를 따지기 때문이고, 두 방식이 섞인 파일은 모든 줄이 바뀐 것처럼 보이는 diff를 만들기 때문입니다.

문자열 밖의 공백은 파서에게 아무 의미가 없으므로 지금까지의 이야기는 유효성에 영향을 주지 않습니다. 영향을 주는 것은 diff이고, 실제로 눈에 띄는 것도 그쪽입니다.

How to do this in code

같은 작업을 코드로 쓰면 이렇습니다. 모두 공백 2칸 들여쓰기를 만들어 내고, 모두 여러분의 숫자도 함께 다시 씁니다. 페이로드에 큰 정수가 없을 때 감수하는 거래입니다.

js JavaScript

세 번째 인자로는 공백 개수 또는 들여쓰기 단위로 쓸 문자열을 넘길 수 있습니다.

const pretty = JSON.stringify(JSON.parse(text), null, 2);

// Tabs
const tabbed = JSON.stringify(JSON.parse(text), null, '\t');
py Python

ensure_ascii의 기본값은 True이며, 악센트가 붙은 문자를 전부 \u 이스케이프로 바꿉니다. 그걸 원하는 사람은 거의 없습니다.

import json

pretty = json.dumps(json.loads(text), indent=2)

# Keep non-ASCII readable rather than escaping it
pretty = json.dumps(json.loads(text), indent=2, ensure_ascii=False)

# From the command line
# python -m json.tool --indent 2 input.json
sh jq

jq는 기본적으로 아무것도 정렬하지 않습니다. 키를 정렬하려면 -S를 붙이세요.

jq . input.json              # 2 spaces, the default
jq --indent 4 . input.json
jq --tab . input.json
jq -c . input.json           # compact
go Go

json.Indent는 표준 라이브러리 중 이 페이지가 하는 일에 가장 가깝습니다. 값을 디코딩하지 않고 바이트를 다시 포맷합니다.

var buf bytes.Buffer
if err := json.Indent(&buf, data, "", "  "); err != nil {
    return err
}

// json.Indent works on raw bytes, so unlike Unmarshal it does
// not touch your numbers at all.
rb Ruby
require 'json'

pretty = JSON.pretty_generate(JSON.parse(text))
php PHP

PHP는 공백 4칸으로 들여쓰며, 이 플래그들을 넘기지 않으면 슬래시와 유니코드를 이스케이프합니다.

$pretty = json_encode(
    json_decode($text),
    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
);

자주 묻는 질문

크기 제한이 있나요?
이 페이지가 두는 제한은 없습니다. 실질적인 상한은 브라우저입니다. JavaScript 엔진은 문자열 하나를 약 512MB로 제한하므로 그보다 큰 것은 애초에 담을 수 없습니다. 10MB 문서를 정렬하는 데 여기서 약 780밀리초가 걸리며, 백그라운드 워커에서 실행되므로 페이지는 계속 반응합니다.
정렬하면 데이터가 바뀌나요?
아닙니다. 문자열 밖의 공백은 JSON에서 의미가 없고, 이 도구는 파싱 후 다시 직렬화하는 대신 작성한 그대로의 값을 다시 내보냅니다. 키 정렬을 켜면 문서가 실제로 바뀌기 때문에 기본값은 꺼짐입니다.
정렬 결과가 제 편집기 출력과 다른 이유는 무엇인가요?
대개는 끝줄 개행이나 객체 배열의 표기 방식 차이입니다. 짧은 배열을 한 줄에 두는 도구도 있지만, 이 도구는 일관된 형식을 유지합니다. 줄 수는 늘지만 diff는 훨씬 읽기 좋아집니다.