이모지 하나, 프로그래밍 언어마다 다른 세 가지 이스케이프 표기
😀 같은 이모지를 소스코드 문자열 안에 안전하게 적으려면 이스케이프 문법을 써야 하는데, 이 문법이 JavaScript·JSON·Python마다 다릅니다. 한 언어에서 복사한 이스케이프 문자열을 다른 언어에 그대로 붙여넣으면 파싱 에러가 나는 이유가 여기 있습니다. 유니코드 변환기의 실제 코드를 확인해 이 도구가 어떤 표기를 만들어내는지, 그리고 각 언어의 규칙이 정확히 무엇인지 정리했습니다.
1. 왜 표기법이 갈라지는가: BMP와 그 바깥
유니코드 코드포인트는 U+0000부터 U+10FFFF까지 존재하지만, 클래식 \uXXXX 이스케이프는 정확히 16비트, 즉 4자리 16진수만 담을 수 있어 U+0000~U+FFFF(기본 다국어 평면, BMP)까지만 표현 가능합니다. 대부분의 이모지는 U+1F300 이상이라 이 범위를 벗어나므로, 언어마다 "BMP 밖 문자를 어떻게 표기할 것인가"에 대해 서로 다른 해법을 택했습니다.
2. JavaScript: 두 가지 문법을 모두 지원
JavaScript는 ES6부터 BMP 밖 문자를 위한 전용 문법 \u{코드포인트}(중괄호)를 추가로 지원합니다. 동시에 구버전 호환을 위해 서로게이트 쌍을 😀처럼 두 개의 4자리 이스케이프로 이어 쓰는 방식도 여전히 유효합니다. 즉 JS 안에서는 같은 문자를 표기하는 방법이 두 가지입니다.
3. JSON: 서로게이트 쌍만 지원, 중괄호 문법 없음
JSON 명세(RFC 8259)는 \uXXXX 4자리 이스케이프만 정의하며, JS의 \u{...} 중괄호 문법은 애초에 JSON 문법에 존재하지 않습니다. 그래서 BMP 밖 문자는 반드시 서로게이트 쌍 두 개로 쪼개 적어야 합니다. JSON.stringify()가 이모지를 만나면 항상 이 방식을 씁니다.
4. Python: 대문자 U + 8자리 고정
Python은 또 다른 방식입니다. 소문자 \u는 JS와 마찬가지로 4자리(BMP 전용)이지만, BMP 밖 문자는 서로게이트 쌍이 아니라 대문자 \U + 8자리 16진수로 코드포인트 전체를 한 번에 씁니다. Python 문자열은 UTF-16이 아니라 코드포인트 시퀀스로 다루어지므로 서로게이트 쌍 개념 자체가 필요 없습니다.
| 언어/포맷 | 표기 | 글자 수 | 비고 |
|---|---|---|---|
| JavaScript (ES6 중괄호) | \u{1F600} | 코드포인트 1개 | JSON에서는 문법 오류 |
| JavaScript (서로게이트 쌍, 구버전 호환) | 😀 | 코드 유닛 2개 | JSON에서도 그대로 유효 |
| JSON | 😀 | 코드 유닛 2개 | 이 표기만 지원, 중괄호 없음 |
| Python | \U0001F600 | 코드포인트 1개 | 대문자 U, 반드시 8자리 |
표에서 보듯 JS의 \u{1F600}을 그대로 JSON 문자열에 넣으면 JSON 파서는 이 문법을 모르므로 파싱 에러를 던집니다. 반대로 JS의 서로게이트 쌍 표기(😀)는 JSON에도 그대로 유효하지만, Python의 \U0001F600을 다른 두 언어에 그대로 붙여넣으면 역시 문법 오류가 납니다. "같은 문자, 다른 표기"가 코드 간 복사·붙여넣기에서 실수를 유발하는 지점입니다.
5. 유니코드 변환기는 실제로 어떤 표기를 생성하는가
unicode-converter.html의 실제 변환 로직을 확인하면, "JS \uXXXX" 출력 열은 코드포인트 값에 따라 자동으로 두 가지 문법을 오간다는 것을 알 수 있습니다.
const jsArr=chars.map(c=>{const cp=c.codePointAt(0);return cp<=0xFFFF?'\u'+cp.toString(16).padStart(4,'0').toUpperCase():'\u{'+cp.toString(16).toUpperCase()+'}';});코드포인트가 0xFFFF 이하(BMP 안)면 클래식 4자리
\uXXXX를, 0xFFFF를 초과하면 ES6 중괄호 \u{코드포인트}를 생성합니다. 이 도구는 JSON용 서로게이트 쌍 표기나 Python용 \U 표기를 별도 열로 제공하지는 않으며, 어디까지나 "JS 문자열 리터럴에 쓸 수 있는 표기"를 만드는 것이 목적입니다.
따라서 유니코드 변환기가 생성한 \u{1F600} 표기를 그대로 JSON 설정 파일이나 API 페이로드에 붙여넣으면 파싱 에러가 납니다. JSON에 넣을 문자열이 필요하다면 이 값을 JSON.stringify()에 한 번 통과시키거나, 도구가 함께 제공하는 U+ 코드포인트 값을 참고해 서로게이트 쌍을 직접 계산해야 합니다. 반대로 입력창에 서로게이트 쌍(😀)을 붙여넣으면, 이 도구는 String.fromCodePoint()로 정상 복원한 뒤 코드포인트 단위 순회로 하나의 문자로 인식해 정확히 디코딩합니다.
6. 코드 간 붙여넣기에서 에러를 피하려면
- 대상이 JSON 문자열/설정 파일이라면 반드시 서로게이트 쌍 표기(
😀)만 써야 합니다. 중괄호 문법은 통하지 않습니다. - 대상이 JS 소스코드라면 두 표기 모두 동작하지만, ES6 이상 환경이 보장된다면 중괄호 표기가 가독성이 더 좋습니다.
- 대상이 Python 소스코드라면 대문자
\U+ 8자리를 써야 하며, 소문자\u4자리로는 BMP 밖 문자를 표현할 수 없어 잘림 오류가 납니다. - 확실하지 않다면 U+ 코드포인트(예: U+1F600) 값을 기준으로 대상 언어 문법에 맞춰 직접 변환하는 것이 가장 안전합니다. 텍스트→유니코드 변환기와 유니코드→텍스트 변환기로 왕복 검증도 가능합니다.
자주 묻는 질문
Q. 유니코드 변환기가 만든 \u{1F600} 표기를 JSON에 그대로 붙여넣어도 되나요?
안 됩니다. JSON 명세는 중괄호 코드포인트 문법을 지원하지 않으므로 파싱 에러가 납니다. 서로게이트 쌍 표기(😀)로 바꿔야 합니다.
Q. Python의 \U0001F600을 JavaScript에서 쓸 수 있나요?
그대로는 안 됩니다. JS는 대문자 \U 8자리 문법을 인식하지 못합니다. 같은 코드포인트를 표현하려면 \u{1F600} 또는 😀로 바꿔 써야 합니다.
Q. BMP 안에 있는 문자(예: 한글, 알파벳)는 언어 간 표기가 동일한가요?
네. U+FFFF 이하 문자는 JS·JSON·Python 모두 소문자 \uXXXX 4자리로 동일하게 표기하며, 서로게이트 쌍이나 중괄호 문법이 필요 없어 언어 간 호환이 됩니다. 문제는 항상 BMP를 벗어나는 문자에서만 발생합니다.
Q. 서로게이트 쌍을 입력창에 붙여넣으면 이 도구가 정상적으로 복원하나요?
네. String.fromCodePoint()로 상위·하위 서로게이트를 조합해 유효한 문자로 복원한 뒤, 코드포인트 단위 순회로 하나의 문자로 정확히 인식합니다.