JSON 문자열 이스케이프란?
JSON 문자열 이스케이프는 문자열 내부의 특수 문자를 JSON 파서가 구조를 깨뜨리지 않고 읽을 수 있는 이스케이프 시퀀스로 변환하는 과정입니다. JSON 명세(ECMA-404 / RFC 8259)는 문자열 값 내의 특정 문자 앞에 백슬래시를 붙이도록 요구합니다. 올바른 이스케이프 처리가 없으면, 문자열 내부의 리터럴 큰따옴표나 줄 바꿈이 문자열을 조기에 종료시켜 파싱 오류를 일으킵니다.
모든 JSON 문자열은 큰따옴표로 구분됩니다. 문자열 자체에 큰따옴표, 백슬래시, 또는 제어 문자(U+0000~U+001F)가 포함되어 있으면 해당 문자를 이스케이프 시퀀스로 대체해야 합니다. 예를 들어 리터럴 줄 바꿈은 \n, 탭은 \t, 큰따옴표는 \"가 됩니다. 모든 유니코드 코드 포인트는 \uXXXX 형식으로도 표현할 수 있으며, 여기서 XXXX는 네 자리 16진수 값입니다.
이스케이프 해제(역 연산)는 백슬래시 시퀀스를 원래 문자로 되돌립니다. JSON 페이로드에서 문자열 값이 이중으로 이스케이프된 경우, 또는 UI나 터미널에 표시하기 위해 JSON 로그 항목에서 원시 텍스트를 추출해야 할 때 사용합니다. 로그 집계 파이프라인에서 이 상황이 자주 발생합니다. JSON으로 인코딩된 메시지가 다른 JSON 문서 내부의 문자열 값으로 저장되면, 내부 문자열의 모든 백슬래시가 두 배로 늘어납니다.
JSON 이스케이프 도구를 사용하는 이유
백슬래시를 수동으로 추가하거나 제거하는 작업은, 특히 여러 줄 텍스트, 파일 경로, 또는 삽입된 코드 스니펫을 다룰 때 지루하고 오류가 발생하기 쉽습니다. 전용 이스케이프 도구는 수동 편집 시 놓치기 쉬운 엣지 케이스를 잡아냅니다.
JSON 문자열 이스케이프 사용 사례
JSON 이스케이프 시퀀스 참조
JSON 명세는 정확히 두 개의 필수 이스케이프(큰따옴표와 백슬래시)와 일반 제어 문자용 여섯 개의 짧은 이스케이프 시퀀스를 정의합니다. 기타 모든 제어 문자(U+0000~U+001F)는 \uXXXX 형식을 사용해야 합니다. U+FFFF 이상의 문자(이모지 등)는 UTF-16 서로게이트 쌍으로 표현할 수 있습니다: \uD83D\uDE00.
| 문자 | 설명 | 이스케이프 형식 |
|---|---|---|
| " | Double quote | \" |
| \ | Backslash | \\ |
| / | Forward slash | \/ (optional) |
| \n | Newline (LF) | \n |
| \r | Carriage return | \r |
| \t | Tab | \t |
| \b | Backspace | \b |
| \f | Form feed | \f |
| U+0000–U+001F | Control characters | \u0000–\u001F |
| U+0080+ | Non-ASCII (e.g. emoji) | \uXXXX or raw UTF-8 |
JSON 이스케이프 vs. JSON 인코딩
개발자들은 때때로 문자열 이스케이프와 전체 JSON 문서 인코딩을 혼동합니다.
코드 예제
모든 주요 언어에는 이를 위한 내장 함수가 있습니다. JavaScript, Python, Go, jq 예제:
// JSON.stringify escapes a value and wraps it in quotes
JSON.stringify('Line 1\nLine 2') // → '"Line 1\\nLine 2"'
// To get just the inner escaped string (no surrounding quotes):
const escaped = JSON.stringify('She said "hello"').slice(1, -1)
// → 'She said \\"hello\\"'
// Parsing reverses the escaping
JSON.parse('"tabs\\tand\\nnewlines"') // → 'tabs\tand\nnewlines'
// Handling Unicode: emoji in JSON
JSON.stringify('Price: 5\u20ac') // → '"Price: 5\u20ac"' (raw euro sign)import json
# json.dumps escapes and quotes a string
json.dumps('Line 1\nLine 2') # → '"Line 1\\nLine 2"'
# Ensure ASCII: replace non-ASCII with \uXXXX sequences
json.dumps('Caf\u00e9', ensure_ascii=True) # → '"Caf\\u00e9"'
# Keep UTF-8 characters as-is (default in Python 3)
json.dumps('Caf\u00e9', ensure_ascii=False) # → '"Caf\u00e9"'
# Unescape by round-tripping through json.loads
json.loads('"She said \\"hello\\""') # → 'She said "hello"'package main
import (
"encoding/json"
"fmt"
)
func main() {
// json.Marshal escapes a Go string for JSON
raw := "Line 1\nLine 2\tindented"
b, _ := json.Marshal(raw)
fmt.Println(string(b))
// → "Line 1\nLine 2\tindented"
// Unescape with json.Unmarshal
var out string
json.Unmarshal([]byte(`"She said \"hello\""`), &out)
fmt.Println(out)
// → She said "hello"
}# Escape a raw string into a JSON-safe value echo 'Line 1 Line 2 with tab' | jq -Rs '.' # → "Line 1\nLine 2\twith tab\n" # Unescape a JSON string back to raw text echo '"She said \"hello\""' | jq -r '.' # → She said "hello"