지식 · 텍스트, 데이터, 보안
유니코드와 UTF-8은 무엇이 다른가요?
핵심 답변
유니코드는 문자 집합입니다. 모든 문자에 코드 포인트라는 번호를 매기며, 예를 들어 "é"는 U+00E9입니다. UTF-8은 인코딩, 즉 그 번호를 바이트로 저장하는 규칙입니다. ASCII는 1바이트, 나머지는 2~4바이트를 쓰므로 "é"는 C3 A9가 됩니다. 유니코드는 어떤 문자인지를, UTF-8은 그것을 디스크에 쓰거나 네트워크로 보내는 방법을 정합니다.
먼저 코드 포인트, 그다음 바이트
유니코드는 U+0000부터 U+10FFFF까지의 코드 공간을 정의합니다. 1,114,112개의 코드 포인트가 들어갈 자리이며, 각각 65,536개씩 17개 평면(plane)으로 나뉩니다. 그중 15만 개 이상이 현대·고대 문자, 기호, 이모지에 할당되어 있습니다. 코드 포인트는 U+ 뒤에 최소 4자리 16진수를 붙여 씁니다.
코드 포인트는 숫자일 뿐입니다. 텍스트를 저장하거나 전송하려면 바이트로 바꿔야 하는데, 그 방법은 여러 가지입니다. UTF-8, UTF-16, UTF-32는 모두 같은 유니코드 문자를 인코딩하는 방식입니다.
| 문자 | 코드 포인트 | UTF-8 바이트 | UTF-16(빅 엔디언) |
|---|---|---|---|
| A | U+0041 | 41 | 00 41 |
| é | U+00E9 | C3 A9 | 00 E9 |
| € | U+20AC | E2 82 AC | 20 AC |
| 日 | U+65E5 | E6 97 A5 | 65 E5 |
| 😀 | U+1F600 | F0 9F 98 80 | D8 3D DE 00 |
UTF-8이 1·2·3·4바이트를 고르는 방법
RFC 3629에 정의된 UTF-8은 가변 길이 인코딩입니다. 첫 바이트의 앞쪽 비트가 뒤에 몇 바이트가 이어지는지 알려 주고, 이어지는 바이트는 모두 10 비트로 시작합니다. 덕분에 스트림이 자기 동기화됩니다. 디코더가 문자 중간에서 읽기 시작해도 다음 시작 바이트로 건너뛸 수 있습니다.
| 코드 포인트 범위 | 바이트 수 | 비트 패턴 |
|---|---|---|
| U+0000 – U+007F | 1 | 0xxxxxxx |
| U+0080 – U+07FF | 2 | 110xxxxx 10xxxxxx |
| U+0800 – U+FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx |
| U+10000 – U+10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
계산 예: "é"는 U+00E9, 2진수로 000 1110 1001입니다. 2바이트 패턴이 필요합니다. 상위 5비트 00011을 110xxxxx에 넣으면 11000011(C3), 하위 6비트 101001을 10xxxxxx에 넣으면 10101001(A9)이 됩니다.
처음 128개 코드 포인트는 ASCII와 같은 1바이트로 인코딩되므로, 올바른 ASCII 파일은 그대로 올바른 UTF-8 파일입니다. 이 하위 호환성이 UTF-8이 웹의 기본 인코딩이 된 가장 큰 이유이며, 현재 웹사이트의 약 98%가 UTF-8을 씁니다.
UTF-8 vs UTF-16 vs UTF-32
| 인코딩 | 단위 크기 | 문자당 바이트 | 주로 쓰이는 곳 |
|---|---|---|---|
| UTF-8 | 8비트 | 1–4 | 웹 페이지, JSON, Linux·macOS 파일, 대부분의 API |
| UTF-16 | 16비트 | 2 또는 4 | JavaScript 문자열, Java, Windows API |
| UTF-32 | 32비트 | 항상 4 | 고정 길이가 유리한 내부 처리 |
UTF-16은 U+FFFF보다 큰 문자를 16비트 단위 두 개로 이루어진 서로게이트 쌍으로 저장합니다. 그래서 JavaScript에서 "😀".length는 2입니다. 이 언어는 문자가 아니라 UTF-16 단위를 세기 때문입니다. [..."😀"].length처럼 순회하면 1이 나옵니다.
영어 텍스트는 UTF-8이 가장 작습니다. 반면 한국어, 중국어, 일본어가 대부분인 텍스트는 UTF-16이 더 작을 수 있습니다. 이런 문자는 UTF-8에서 3바이트, UTF-16에서 2바이트를 차지하기 때문입니다.
바이트 순서 표식(BOM)
BOM은 파일 맨 앞에 놓이는 문자 U+FEFF입니다. UTF-16과 UTF-32에서는 바이트가 빅 엔디언인지 리틀 엔디언인지 알려 줍니다. UTF-8에서는 EF BB BF로 인코딩되며, UTF-8에는 바이트 순서가 없으므로 서명 역할만 합니다.
유니코드 FAQ는 UTF-8 BOM이 필요하지도, 권장되지도 않는다고 말합니다. 그런데도 일부 Windows 편집기는 BOM을 붙이며, 그러면 셸 스크립트(#! 줄이 더 이상 맨 앞이 아님), CSV 헤더, BOM을 예상하지 않는 JSON 파서가 깨집니다. 파일 맨 앞에 가 보인다면 UTF-8 BOM을 Windows-1252로 읽은 것입니다.
글자가 é나 ���로 깨지는 이유
모지바케(mojibake)라 부르는 글자 깨짐은, 바이트를 기록할 때와 다른 인코딩으로 디코딩할 때 나타납니다.
é대신é: UTF-8 바이트C3 A9를 Windows-1252나 Latin-1로 읽어C3이Ã,A9가©로 대응된 경우입니다.�(U+FFFD, 대체 문자): 디코더가 올바른 UTF-8이 아닌 바이트를 만난 경우로, Latin-1 텍스트를 UTF-8로 읽었을 때 흔합니다.- 데이터베이스의 물음표: 칼럼이나 연결의 문자 집합이 해당 문자를 담을 수 없어 저장할 때 대체되었고, 원래 문자는 사라진 경우입니다.
해결책은 모든 경계에서 인코딩을 명시하는 것입니다. HTML에는 <meta charset="utf-8">, HTTP 헤더에는 Content-Type: text/html; charset=utf-8, 데이터베이스 칼럼과 연결에는 UTF-8을 지정하세요. MySQL에서는 utf8mb4를 쓰세요. 예전 utf8 문자 집합은 문자당 최대 3바이트만 저장해 이모지를 거부합니다.
자주 묻는 질문
UTF-8과 유니코드는 같은 건가요?
아니요. 유니코드는 문자와 그 번호의 목록이고, UTF-8은 그 번호를 바이트로 저장하는 방식 중 하나입니다. 흔히 UTF-8 텍스트를 가리켜 "유니코드"라고 부르기도 합니다.
UTF-8에서 한 글자는 몇 바이트인가요?
1~4바이트입니다. ASCII 문자는 1바이트, 유럽 언어의 악센트 문자는 대부분 2바이트, 한중일 문자는 대부분 3바이트, 이모지는 4바이트입니다.
UTF-8로 모든 문자를 표현할 수 있나요?
네. UTF-8은 U+0000부터 U+10FFFF까지 모든 유니코드 코드 포인트를 인코딩할 수 있으므로, 유니코드가 정의한 문자는 모두 UTF-8로 쓸 수 있습니다.
파일을 BOM과 함께 저장해야 하나요?
UTF-8이라면 보통 그럴 필요가 없습니다. 선택 사항이고 바이트 순서 측면에서 의미가 없으며, 첫 바이트가 내용이라고 기대하는 도구를 혼란스럽게 합니다. 다만 일부 구버전 Excel은 UTF-8 CSV 파일을 제대로 열려면 BOM이 필요합니다.