JSON 문자열 변환

입력한 내용은 저장, 기록, 공유되지 않습니다.

JSON을 코드에 붙여넣을 수 있는 이스케이프 문자열로 바꾸거나, 이스케이프된 문자열을 읽기 쉬운 JSON으로 되돌립니다.

사용 방법

  1. 이스케이프하려면 문자열 변환을, 되돌리려면 복원을 선택합니다.
  2. 입력창에 JSON을 붙여넣습니다.
  3. 복사 버튼으로 결과를 복사합니다.

이스케이프가 실제로 하는 일

문자열화는 JSON을 파싱해 압축한 뒤, 결과를 큰따옴표로 감싸고 문자열을 일찍 끝나게 만들 수 있는 모든 것을 이스케이프합니다. 내부의 큰따옴표는 \"가 되고, 백슬래시는 \\로 두 배가 되며, U+0020 미만의 제어 문자는 짧은 형태인 \n, \r, \t, \b, \f로, 짧은 형태가 없는 것은 \u00XX 이스케이프로 바뀝니다.

일부러 건드리지 않는 것이 두 가지 있습니다. 슬래시는 JSON이 요구하지 않으므로 이스케이프하지 않습니다. 다른 도구의 출력에서 \/를 보기도 하는데, 이는 합법이지만 불필요한 표기로, HTML 안에서 </script>라는 문자열을 숨기던 옛 습관에서 비롯되었습니다. 비ASCII 문자도 \u 이스케이프로 바꾸지 않고 그대로 두므로 악센트가 붙은 문자, 한글 같은 CJK 문자, 이모지도 읽을 수 있는 상태로 남습니다. 두 형태는 파서에게 같은 의미이며, 읽을 수 있는 쪽이 비교하기 더 쉽습니다.

이중 인코딩과 그것이 골치 아픈 이유

이 도구가 존재하는 이유는 이스케이프가 멱등하지 않기 때문이며, 사람들은 대개 다른 문제를 디버깅하다가 이 사실을 알게 됩니다. 문서를 한 번 이스케이프하면 따옴표가 \"가 됩니다. 그 결과를 다시 이스케이프하면 \\\"가 되는데, 방금 추가한 백슬래시 자체가 이스케이프해야 하는 문자가 되기 때문입니다. 한 번 거칠 때마다 백슬래시가 대략 두 배로 늘어납니다.

이것은 두 번 직렬화된 페이로드의 특징입니다. 객체가 들어 있어야 할 필드에 JSON 문자열이 들어 있고, 로그를 보면 따옴표 앞에 백슬래시가 붙어 있는 것이 보입니다. 프레임워크가 이미 직렬화한 값에 코드가 직렬화 함수를 한 번 더 호출할 때 생기며, 해결책은 거의 항상 디코딩 단계를 추가하는 것이 아니라 두 호출 중 하나를 없애는 것입니다.

이를 풀어내는 도구가 문자열화 해제입니다. 인코딩 한 겹마다 한 번씩 실행하면 백슬래시가 매번 절반으로 줄어드는 것을 볼 수 있습니다. 백슬래시가 사라지고 결과가 객체로 파싱되면, 몇 겹이었는지 알게 됩니다.

이스케이프된 문자열이 필요한 경우

다른 JSON 문서 안에 페이로드를 넣을 때입니다. 웹훅 봉투, 작업 큐, 감사 로그는 임의의 본문을 대개 이렇게 담습니다. 환경 변수에 JSON 값을 설정할 때도 그렇습니다. 그렇지 않으면 셸이 따옴표를 먹어 버립니다. CI 작업의 YAML 파일에 요청 본문을 붙여 넣을 때, 소스 코드에 테스트 픽스처를 리터럴로 쓸 때, 네이티브 JSON 열이 아니라 텍스트 열에 문서를 저장할 때도 마찬가지입니다.

어느 경우든 안쪽의 따옴표는 그대로 두면 끝 표시로 취급될 파싱 단계를 통과해야 하며, 이스케이프가 그것들을 온전하게 통과시켜 줍니다.

이스케이프 규칙을 한 글자씩

JSON은 문자열 안에 그대로 쓸 수 없는 문자를 정확히 규정합니다. 큰따옴표는 문자열을 그 자리에서 끝내 버리므로 \"가 됩니다. 백슬래시는 이스케이프의 시작이므로 \\로 두 번 씁니다. U+0020보다 낮은 제어 문자는 모두 금지되며, 그중 다섯 개는 짧은 형태가 있습니다. 줄바꿈은 \n, 캐리지 리턴은 \r, 탭은 \t, 백스페이스는 \b, 폼 피드는 \f입니다. 그 범위의 나머지 문자는 \u0000 같은 여섯 글자짜리 이스케이프가 됩니다.

꼭 필요하지 않은데도 흔히 이스케이프되는 문자가 둘 있습니다. 슬래시는 \/로 쓸 수 있는데, 문법상 허용되지만 불필요합니다. 이 습관은 JSON을 HTML 안에 넣던 관행에서 왔습니다. 그대로 두면 </script>라는 연속된 문자가 script 요소를 먼저 닫아 버리기 때문입니다. ASCII가 아닌 문자도 \u 이스케이프로 쓸 수 있고, 출력을 순수 ASCII로 유지하려고 기본값으로 그렇게 하는 라이브러리도 있습니다.

이 도구는 둘 다 건드리지 않습니다. 읽기 좋은 출력이 diff를 뜨기에 낫고, 어떤 파서든 두 형태를 똑같이 취급하기 때문입니다. 뒤쪽 시스템이 정말로 ASCII만 필요하다면, 그것은 직렬화기의 옵션 문제이지 문서 자체가 요구하는 사항이 아닙니다.

셸을 통해 JSON을 안전하게 넘기기

이스케이프가 가장 자주 어긋나는 곳은 셸입니다. 따옴표 계층이 한꺼번에 둘 적용되기 때문입니다. bash의 작은따옴표는 안에 있는 모든 것을 그대로 통과시키며, 그래서 curl -d '{"name":"value"}'는 동작하고 같은 문자열을 큰따옴표로 감싸면 동작하지 않습니다. 셸이 변수를 확장하고 일부 문자를 없앤 뒤에야 curl이 그 값을 보게 되기 때문입니다.

본문 자체에 작은따옴표가 들어 있으면 작은따옴표 방식도 깨집니다. 확실한 해법은 아예 명령줄에 넣지 않는 것입니다. 본문을 파일로 쓰고 curl -d @body.json을 쓰거나 파이프로 넣으면 됩니다. 프로그램이 만들어 내는 본문이라면 문자열을 이어 붙이는 것보다 jq -n이 안전합니다. 구조적으로 올바른 JSON이 나오기 때문입니다.

JSON을 담은 환경 변수도 같은 계열의 문제이며, 특히 CI 설정과 Docker에서 자주 생깁니다. 그 값은 보통 YAML의 따옴표 처리, 셸 확장, 애플리케이션 자체의 파싱이라는 세 계층을 모두 견뎌야 합니다. 정신을 붙들 방법은 JSON을 base64로 인코딩해 넘기고 쓰는 지점에서 디코딩하는 것입니다.

구조화 로그와 이중 인코딩의 흔적

로그 파이프라인은 점점 한 줄에 JSON 객체 하나를 기대합니다. 그래야 자유 형식 텍스트에 정규식을 돌리는 대신 필드를 검색할 수 있기 때문입니다. 함정은 이미 직렬화된 객체를 로그로 남기는 것입니다. 그 필드는 중첩된 객체가 아니라 JSON 문자열로 도착하고, 로그 시스템은 그것을 불투명한 덩어리 하나로 색인합니다.

눈에 보이는 신호는 바로 이 도구가 풀어내려는 그 흔적입니다. 값이 {"id":42}가 아니라 {\"id\":42}처럼 읽히는 것이죠. 계층이 하나 늘 때마다 백슬래시는 대략 두 배가 되므로, 개수를 세어 보면 몇 번 인코딩됐는지 알 수 있습니다.

고칠 자리는 생산자 쪽입니다. 직접 직렬화해 문자열을 넘기지 말고, 객체를 로거에 그대로 넘겨 한 번만 직렬화하게 하십시오. 문자열이 외부에서 들어오고 바꿀 수 없다면, 대부분의 로그 플랫폼에는 수집 시점에 해당 필드를 풀어 주는 JSON 파싱 필터가 있습니다. 질의할 때마다 푸는 것보다 그 편이 낫습니다.

다른 문서 안에 페이로드 넣기

웹훅 봉투, 작업 큐, 감사 로그는 모두 같은 문제를 마주합니다. 자체 필드를 가진 껍데기가 임의의 본문을 실어 날라야 한다는 것입니다. 그 본문을 문자열로 직렬화하는 것이 간단한 답이고, 대가는 안쪽 문서가 불투명해진다는 점입니다. 한 번 더 파싱하지 않으면 질의도 검증도 색인도 할 수 없습니다.

대안인, 본문을 중첩 객체로 두는 방식은 질의 가능성을 지켜 주지만 껍데기의 스키마가 임의 구조를 허용해야 하고, 문서를 훑는 쪽에서 보면 두 이름 공간이 뒤섞입니다. 대부분의 시스템은 쓰임새마다 따로 정하는 데서 멈춥니다. 본문을 들여다봐야 하면 중첩으로, 그저 전달만 한다면 문자열로 말이죠.

페이로드가 크거나 바이너리일 때 기억해 둘 만한 세 번째 선택지가 있습니다. 실물은 다른 곳에 두고 참조만 보내는 것입니다. 봉투에 URL과 체크섬을 넣으면 이스케이프 문제와 크기 제한을 둘 다 피할 수 있고, 큰 파일을 다루는 작업 흐름은 어차피 대개 그렇게 귀결됩니다.

도구 없이 이스케이프된 텍스트 읽기

짧은 값이라면 눈으로 인코딩을 되돌리는 일이 충분히 가능하고 연습해 둘 가치도 있습니다. 무슨 일이 있었는지 알 수 있기 때문입니다. 한 겹이면 키와 값 주위에 \"가 보입니다. 두 겹이면 \\\"가 보이고, 문자열 전체도 그 자체가 이스케이프된 따옴표로 감싸여 있는 것이 보통입니다. 그보다 깊어지면 백슬래시가 내용보다 많아져서 읽는 것보다 세는 편이 빠릅니다.

쓸 만한 확인법은 문자열의 시작입니다. 제대로 중첩된 객체는 이스케이프되지 않은 중괄호로 시작하고, 두 번 인코딩된 것은 따옴표 뒤에 이스케이프된 중괄호가 옵니다. 이 모양은 곧 한눈에 알아보게 됩니다.

터미널에서는 printf '%s\n' "$value"가 한 겹을 풀고 jq -r '.'가 한 겹을 더 풉니다. 차례로 적용하면서 백슬래시가 매번 절반으로 줄어드는 것을 보는 것이, 여기 있는 unstringify 버튼이 하는 일의 명령줄 판입니다.

자주 묻는 질문

문자열 변환은 실제로 무엇을 하나요?
JSON을 검증하고 압축한 뒤 전체를 따옴표로 감싸고 내부의 따옴표와 제어 문자를 이스케이프합니다. 소스 코드에 바로 넣을 수 있는 문자열 리터럴이 만들어집니다.
이스케이프된 JSON 문자열은 언제 필요한가요?
JSON을 다른 JSON, 셸 명령, 환경 변수, 테스트 픽스처 안에 넣을 때 주로 필요합니다. 그대로 넣으면 내부 따옴표가 문자열을 일찍 끝내버립니다.
복원할 때 따옴표로 감싼 문자열이 아니라는 오류가 나오는 이유는?
복원은 전체가 큰따옴표로 감싸인 문자열 리터럴을 기대합니다. 일반 객체를 붙여넣었다면 문자열 변환을 사용하세요.
데이터가 서버로 전송되나요?
아닙니다. 이스케이프 처리는 브라우저의 JavaScript로만 실행되므로 데이터가 기기를 벗어나지 않습니다.

마지막 업데이트:

문제 신고

진행 단계, 예상 결과, 실제 결과를 적어 주세요. 비밀 정보와 개인 정보는 삭제해 주세요.

관련 도구