문자 인코딩
글자를 수로 바꿔 바이트에 적는 규칙입니다. 컴퓨터가 다루는 것은 바이트뿐입니다. 그래서 글자마다 붙인 번호를 바이트로 적기로 미리 약속합니다. 적는 쪽과 읽는 쪽이 같은 약속을 써야 글자가 그대로 돌아옵니다.
상세
학교에서 학생마다 학번을 매깁니다. 학번을 명부에 몇 자리로 적을지는 그와 별개로 따로 정합니다.
번호를 매기는 일과 그 번호를 적는 일이 다른 일이라는 것이 이 표제어의 핵심입니다. Unicode 기술 보고서 17번은 이것을 네 계층으로 나눕니다.
- ACR(Abstract Character Repertoire, 추상 문자 레퍼토리)은 부호화할 문자의 집합입니다. 어떤 알파벳이나 기호 집합 같은 것이 그 예입니다.
- CCS(Coded Character Set, 부호화 문자 집합)는 추상 문자 레퍼토리에서 음이 아닌 정수의 집합으로 가는 특정한 대응입니다. 그 정수들이 연속일 필요는 없습니다.
- CEF(Character Encoding Form, 문자 인코딩 형식)는 부호화 문자 집합의 원소인 음이 아닌 정수들을, 정해진 폭을 가진 특정 코드 유닛의 열로 옮기는 특정한 대응입니다. 32비트 정수 같은 것이 그 폭의 예입니다.
- CES(Character Encoding Scheme, 문자 인코딩 스킴)는 하나 이상의 문자 인코딩 형식에서 나온 코드 유닛 열을, 직렬화된 바이트 열로 옮기는 되돌릴 수 있는 변환입니다.
flowchart TD
A[추상 문자 레퍼토리] --> B[부호화 문자 집합]
B --> C[문자 인코딩 형식]
C --> D[문자 인코딩 스킴]
D --> E[직렬화된 바이트 열]
같은 문서는 코드 포인트를 이 대응 위에서 정의합니다. 추상 문자는 부호화 문자 집합이 그것을 정수로 대응시킬 때 그 집합 안에 있다고 정의됩니다. 그 정수가 그 추상 문자에 배정된 코드 포인트입니다.
계층이 갈려 있으니 같은 코드 포인트라도 어느 인코딩 형식과 어느 인코딩 스킴을 거치느냐에 따라 다른 바이트 열이 됩니다. 반대 방향도 마찬가지입니다. 인코딩 스킴은 코드 유닛 열에서 바이트 열로 가는 변환입니다. 바이트 열만으로 어느 스킴인지가 늘 정해지지는 않습니다. 그래서 이 바이트가 무슨 글자냐는 물음은 규칙을 함께 알아야 답이 정해집니다.
배경
컴퓨터가 저장하거나 주고받는 것은 바이트입니다. 글자는 바이트가 아닙니다. 그래서 글자를 다루려면 글자마다 수를 하나 정하는 약속과 그 수를 바이트로 적는 약속이 먼저 있어야 합니다.
약속은 한 벌만 생기지 않았습니다. 쓰는 글자가 지역마다 다르니 같은 바이트 값에 서로 다른 글자를 앉힌 약속들이 따로 자랐습니다. 그러면 바이트가 같아도 어느 약속으로 읽느냐에 따라 다른 글자가 나옵니다. 무엇이 어긋났는지를 말하려면 어긋날 수 있는 자리마다 이름이 따로 있어야 합니다.
정리는 계층을 가르는 쪽으로 갔습니다. RFC(Request for Comments, 의견 요청) 2130은 IAB(Internet Architecture Board, 인터넷 아키텍처 위원회) 문자 집합 워크숍의 보고서입니다. 이 문서는 아키텍처 모델이 7개 계층을 명시한다고 적습니다. 그 가운데 셋만 회선 전송에 필요합니다. 부호화 문자 집합은 추상 문자의 집합에서 정수의 집합으로 가는 대응입니다. 문자 인코딩 스킴은 하나 또는 여러 부호화 문자 집합에서 옥텟의 집합으로 가는 대응입니다. TES(Transfer Encoding Syntax, 전송 인코딩 구문)는 문자 인코딩 스킴으로 부호화된 데이터에 적용해 그것이 전송될 수 있게 하는 변환입니다. Unicode 기술 보고서 17번은 자기 구조가 이것을 넓힌 것이라고 밝힙니다. RFC 2130의 IAB 세 계층 text stream 정의를, Unicode 표준을 설명하기에 더 적절한 네 계층 구조로 정교화했다는 것입니다. 같은 문서는 RFC 2130 3.2절의 IAB 모델이 세 수준을 구분한다고 적습니다. Unicode 문자 인코딩 모델이 요구하는 구분을 충분히 덮으려면 네 수준을 정의해야 한다고도 적습니다.
실패
적는 쪽과 읽는 쪽이 다른 규칙을 쓰면 바이트는 그대로여도 나오는 글자가 달라집니다. 읽는 쪽 규칙이 그 바이트 열을 아예 받아들이지 못하는 경우도 있습니다. 그 자리에 무엇이 나오는지는 규격이 정해 두었습니다.
Unicode 용어집은 대체 문자를 다른 인코딩에서 온 해석할 수 없는 문자를 대신하는 데 쓰이는 문자로 정의합니다. Unicode 표준은 이 기능에 U+FFFD REPLACEMENT CHARACTER 를 씁니다.
Unicode 기술 FAQ(Frequently Asked Questions, 자주 묻는 질문)는 잘못된 바이트열을 만났을 때의 처리를 적어 두었습니다. 규정을 받는 쪽은 적합한 UTF-8(Unicode Transformation Format 8-bit, 유니코드 변환 형식 8비트) 처리기입니다. 오류를 알리거나, 그 바이트를 걸러 내거나, U+FFFD REPLACEMENT CHARACTER 같은 표시로 그 바이트를 나타내는 것이 그 예입니다. 적합한 처리기는 불법이거나 잘못 형성된 바이트열을 문자로 해석해서는 안 됩니다. 다만 오류 복구 조치는 취할 수 있습니다.
되돌리기가 늘 되지는 않는 이유가 여기에 있습니다. 걸러 내는 처리와 표시로 나타내는 처리는 원래 바이트를 결과에서 빼거나 표시 하나로 바꿉니다. 그러면 결과만 들고는 원래 바이트 값을 다시 세울 근거가 남지 않습니다.
웹 쪽 규격은 이것을 모드로 이름 붙여 놓았습니다. 그 규격을 낸 곳이 WHATWG(Web Hypertext Application Technology Working Group, 웹 하이퍼텍스트 애플리케이션 기술 작업 그룹)입니다. WHATWG Encoding Standard 는 오류 모드가 디코더에 대해서는 replacement 이거나 fatal 이라고 적습니다. 인코더에 대해서는 fatal 이거나 html 이라고 적습니다. 같은 문서의 디코딩 단계는 결과가 오류일 때 모드가 replacement 이면 출력에 U+FFFD 를 밀어 넣습니다. 그 규격이 정의한 UTF-8 디코더의 제약이 Unicode 표준의 Best Practices for Using U+FFFD 와 일치한다고도 적습니다.
| 상황 | 정해진 처리 |
|---|---|
| 적합한 UTF-8 처리기가 잘못 형성된 바이트열을 만남 | 오류를 알리거나, 그 바이트를 걸러 내거나, U+FFFD 로 나타냅니다 |
| 오류 모드가 replacement 인 디코더에서 결과가 오류임 | 출력에 U+FFFD 를 밀어 넣습니다 |
| 라벨 문자열이 표의 어느 라벨과도 안 맞음 | failure 를 돌려줍니다 |
마지막 줄은 이름을 못 알아보는 실패입니다. 같은 규격은 문자열 라벨에서 인코딩을 얻는 절차를 정해 두었습니다. 먼저 라벨 앞뒤의 ASCII(American Standard Code for Information Interchange, 미국 정보 교환 표준 부호) 공백을 지웁니다. 표에 실린 라벨 가운데 ASCII 대소문자를 무시했을 때 맞는 것이 있으면 그에 대응하는 인코딩을 돌려줍니다. 맞는 것이 없으면 failure 를 돌려줍니다.
HTML(HyperText Markup Language, 하이퍼텍스트 마크업 언어) 쪽 규격도 절차를 하나 정해 두었습니다. WHATWG HTML Standard 는 사용자 에이전트가 첫 번째 패스에서 문서를 디코딩할 때 쓸 문자 인코딩을 정하기 위해, 인코딩 스니핑 알고리즘이라고 부르는 알고리즘을 써야 한다고 적습니다.
예시
UTF-8 의 바이트 패턴
RFC 3629 는 코드 포인트 범위마다 쓰는 바이트 수를 표로 적었습니다. 각 바이트의 어느 비트가 값을 나르는지도 같은 표에 실려 있습니다.
Char. number range | UTF-8 octet sequence
(hexadecimal) | (binary)
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
같은 문서의 예시 절은 실제 값을 답니다. 코드 포인트 열 U+D55C U+AD6D U+C5B4 는 한국어라는 뜻의 한국어 낱말입니다. UTF-8 에서 다음과 같이 부호화됩니다.
ED 95 9C EA B5 AD EC 96 B4
코드 포인트는 셋입니다. 바이트는 아홉입니다. 글자에 붙은 번호와 그 번호를 적은 바이트가 다른 계층에 있다는 것이 이 한 줄에 그대로 보입니다.
Content-Type 헤더의 charset 파라미터
RFC 9110 은 미디어 타입을 나르는 필드의 예로 한 줄을 답니다.
Content-Type: text/html; charset=ISO-8859-4
바이트를 받는 쪽이 어느 규칙으로 읽어야 하는지를 바이트 바깥에서 함께 알려 주는 자리입니다.
한국어 인코딩의 이름
RFC 1557 은 인터넷 메시지에서 쓸 한글 인코딩 스킴의 이름을 ISO-2022-KR 로 정합니다. MIME(Multipurpose Internet Mail Extensions, 다목적 인터넷 메일 확장) 메시지 형식이 그 이름을 씁니다. 쓰인 모습은 다음과 같습니다.
Content-Type: text/plain; charset=iso-2022-kr
같은 문서는 메시지의 헤더 부분에 부호화되는 한글은 Korean EUC 라고 적습니다. EUC-KR 부호화에서 여덟 번째 비트가 세워진 바이트는 KSC-5601 문자로 인식됩니다. 그때 쓸 이름은 EUC-KR 이라고 적습니다.
이름은 레지스트리에도 값으로 올라 있습니다. 그 레지스트리를 두는 곳이 IANA(Internet Assigned Numbers Authority, 인터넷 할당 번호 관리 기관)입니다. IANA 문자 집합 레지스트리는 EUC-KR 을 번호 38 로, 별칭 csEUCKR 과 함께 올려 두었습니다. KS_C_5601-1987 은 번호 36 입니다. 별칭으로는 iso-ir-149 · KS_C_5601-1989 · KSC_5601 · korean · csKSC56011987 이 실려 있습니다.
관련 항목
이것을 이루는 구성 요소
ACR · CCS · CEF · CES · TES · 코드 포인트 · 코드 유닛 · 옥텟 · 서로게이트
번호를 정하는 표준
유니코드 · ASCII · ISO/IEC 8859 · KS X 1001 · KSC-5601
실제로 쓰이는 인코딩 스킴
UTF-8 · UTF-16 · UTF-32 · EUC-KR · CP949 · ISO-2022-KR
인코딩을 알리는 수단
Content-Type charset · meta charset · 로케일 · IANA 문자 집합 레지스트리 · 바이트 순서 표시 · MIME · HTML
다른 표현을 같다고 보게 하는 절차
유니코드 정규화 · 대소문자 접기 · 결합 문자 · 문자소 클러스터
규격이 정한 오류 처리
대체 문자 · 오류 모드 · 인코딩 스니핑 알고리즘
실무에서 부르는 오류 현상
모지바케 · 이중 인코딩 · 잘린 멀티바이트 · 이모지 길이 오계산
이것을 정의하는 표준·문서
RFC · RFC 2130 · RFC 3629 · RFC 9110 · RFC 1557 · WHATWG Encoding Standard · WHATWG HTML Standard
이 규격들을 만드는 기구
다른 이름: character encoding · 문자 부호화 · 캐릭터 인코딩