문자 인코딩의 역사를 알아보자

Feb 11, 2025

개요

Java의 파일 I/O와 Stream에 대해 공부하다가 문득 ‘UTF-8은 왜 표준이 된걸까?’ 라는 의문이 생겼습니다.

그러다가 문자(character) 인코딩의 기원까지 찾아가는 샛길로 빠져버렸는데요, 꽤나 재미있는 내용이어서 한 번 정리해봤습니다.

문자’라는 것은 인류 문명에서 빼놓을 수 없는 문화 중 하나로, 최초의 상형 문자로 알려진 수메르 문명의 ‘쐐기문자’부터 현대까지 이어진 인간의 시각적 관행인데요 아날로그에서 디지털로 넘어오는 순간에도 이 문자의 중요성은 여전했습니다.

이번 글의 메인 스트림은 문자가 디지털 시대를 거치며 생긴 변천사를 알아보는 것입니다.

시간 순으로 알아보는 인코딩의 발전

인코딩(Encoding)

내용 이해를 위해 간단한 질문으로 시작합니다.

인코딩(Encoding)의 정의가 무엇일까요? 인코딩원본 정보약속된 형태(코드) 로 바꾸는 작업입니다.

일반적인 컴퓨터는 이진수(0과 1) 로 모든 데이터를 저장하고 처리합니다. 그러나 사람이 사용하는 문자(한글, 영어, 숫자, 특수문자 등)는 직접 이진수로 표현되지 않기 때문에 문자를 숫자로 변환하는 규칙(인코딩 방식)이 필요성이 생겼습니다.

모스 코드(부호)

저같은 경우 ‘모스 부호’라는 것을 영화에서 구조 신호로 사용하는 것을 많이 봤었는데요, 이는 미국의 새뮤얼 모스라는 화가 겸 발명가가 고안한 전신 기호(telegraphic code) 입니다.

여기서 전신 기호는 서로 떨어진 곳에서 전류나 전파를 이용하여 정보를 약속된 신호로 주고받는 통신 방법 중의 하나입니다.

화가였던 모스는 1825년에 고향을 떠나 워싱턴에서 미국 독립전쟁의 영웅 ‘라파예트 후작’의 초상화를 그리고 있을 때 말을 타고 급히 달려온 메신저가 ‘아내가 아프다’는 내용의 아버지가 쓴 편지를 전해받았습니다.

모스는 즉시 뉴헤이븐에 있는 집으로 돌아갔지만, 아내는 이미 세상을 떠났고 장례식까지 끝난 뒤였습니다.

아내의 임종을 하지 못한데 자책감을 느낀 모스는 화가의 꿈을 접고 ‘어떻게 하면 소식을 빠르게, 멀리까지 전달할 수 있을까?’ 라는 생각에 골몰한 끝에 1837년에 모스 전신기를 만들었습니다.

모스 부호를 사용한 전신이 소개되기 훨씬 전에 인류는 봉화(beacon)나 깃발을 사용해 장거리에서 메시지를 변환하여 알리곤 했지만, 모스 부호가 가지는 상징성은 영어 알파벳의 각 문자에 대한 표준 인코딩 방법을 갖는 최초의 시스템이라는 것입니다.

이는 현대 문자 인코딩 시스템에서 무시할 수 없는 기반이 되었죠.

펀치 테이프, 카드(천공 테이프)

모스 부호 기반의 전신 기술이 발전하면서, 전신 기계의 메시지를 자동 기록하기 위해 천공 테이프가 도입되었습니다.

당시 컴퓨터는 키보드와 디스플레이가 없고 하는 일은 연산 작업에 가까웠기 때문에, 위 사진과 같이 종이로 만든 천공 테이프(punched tape)를 사용해 입출력 작업을 수행해야 했습니다. (여기서 천공(穿孔) 이라는 것은 구멍이 뚫려있는 상태를 말합니다.)

천공 테이프는 구멍을 뚫거나 뚫지 않음으로 0과 1을 표시할 수 있었으며, 이는 이진법으로 비트를 구현하는 매체라는 의미입니다.

그런데 당시에 데이터를 표현하기 위해 펀치 테이프를 사용하는 방법에 대한 통일된 ‘표준’이 없었기 때문에 불필요한 펀치 테이프가 낭비되는 일이 잦았습니다.

또한 저장 밀도가 낮아서 1mb의 데이터를 저장하려면 약 10km 이상의 천공 테이프가 필요할 정도로 비효율적이었으며, 테이프가 엉키거나 꼬이면 다시 풀어야 하는 번거로움도 있었죠.

그래서 1960년대에 ANSI(American National Standard Institute, 미국 국가표준 협회) 는 데이터 처리를 위한 공통 코드를 개발하는 프로젝트를 주도했고, 이는 ASCII의 탄생으로 이어졌습니다.

ASCII(American Standard Code for Information Interchange, 미국 정보 교환 표준 부호)

사실 ASCII 이전에 프랑스 전신 기술자 에밀 보도가 전신 회선을 통해 문자를 전송할 수 있는 5비트 바이너리 코드를 발명했습니다.

‘보도 코드’로 알려진 이 코드는 전신에 널리 채택되어 수년 동안 사실상 표준이 되었고 대문자와 소문자, 숫자 및 일부 특수 문자를 전송할 수 있었습니다.

그러나 라틴 문자가 아닌 문자를 표현하는 데 제한이 있었고 결국 후술할 ASCII 같은 진보된 표준으로 대체되었습니다.

ASCII 코드는 IBM의 컴퓨터 프로그래머이자 엔지니어인 밥 베머가 1961년에 ASA(American Standards Association) 에 컴퓨터용 표준 문자 인코딩 시스템에 대한 제안을 제출한 것이 시작점입니다.

IBM 704 모델에서 사용되는 6비트 바이너리 코드를 기반으로 하는 베머의 제안에는 대문자와 소문자, 숫자, 특수 문자에 대한 조항이 포함되어 있었는데요, 이는 결국 2년 후에 발표된 ASCII 표준으로 통합됩니다.

확장 ASCII(Extended ASCII)

이렇게 탄생한 ASCII는 인간과 컴퓨터 간 상호작용 문제를 해결하고 꾸준히 개선해나갔지만, 0x00부터 0x7F까지의 총 127개 문자(제어 문자, 특수 문자, 숫자, 알파벳 등)만이 포함되어있다는 한계점이 있었습니다.

이말은 즉슨 영어로만 컴퓨터와 통신할 수 있다는 의미입니다.

이를 해결하기 위해 확장 ASCII(Extended ASCII)를 제정하여 기존의 ASCII로 정의하지 못했던 128번부터 255번까지의 새로운 문자를 정의할 수 있게 되었는데, 새로 추가된 128개의 코드(0x80 ~ 0xFF)로 프랑스어, 독일어 등의 유럽어를 표현할 수 있도록 만들었습니다.

이와 같이 다양한 유럽어를 표현할 수 있는 확장 ASCII는 ISO-8859 유럽 통일 표준안으로 제정되었고, 수년간의 개선 끝에 255개의 문자와 그에 대응하는 이진 형식으로 구성되어 대부분의 유럽 국가 언어도 지원하게 되었습니다.

아시아 문자 집합(Asian Character Sets)과 한글 인코딩

1980년대에 들어 아시아 국가들이 성장하면서 각자 자국어를 지원하는 문자 인코딩 시스템을 설계하기 시작했습니다.

한국에서는 1980년대 초부터 여러 인코딩 방법 도입을 시도했는데요, 한 번 살펴보겠습니다.

한글 조합형 인코딩

조합형 인코딩 방식은 한글을 초성, 중성, 종성으로 나누어 각각의 낱자를 조합하여 표현하는 방식으로, ‘한글’이라는 단어를 ‘ㅎㅏㄴㄱㅡㄹ’로 낱자를 조합하여 표현하는 것입니다.

완성형 자모로 결합한 모든 글자를 표현할 수 있다는 장점이 있지만, 용량 효율성 면에서 좋지 않았습니다.

예를 들어서 “가”는 2바이트지만, 받침이 있는 경우 3~5바이트가 될 수도 있다는 것이죠.

한글 완성형 인코딩과 조합형의 사멸

완성형 인코딩은 초성, 중성, 종성을 조합하지 않고 미리 만들어진 “완성된 한글 음절”을 코드로 저장하는 방식입니다.

외국어 및 특수문자를 미리 가정하고 만들었기 때문에 조합형에 비해 국제 표준과 충돌이 적다는 장점이 있었지만, 미리 조합되어 있는 글자 외의 문자는 어떻게 해도 표시할 수 없다는 단점도 있었습니다.

사용되는 모든 글자가 포함된다면 문제가 없겠지만, 1987년에 최초로 만들어진 기본 완성형 코드의 한글 글자 수는 2350자가 전부였는데, 현대에 사용되는 한글 11,172자에 비하면 크게 부족했습니다.

이는 당시에 PC통신망에서만 논쟁거리였던 것이 아니라 실제 기업들의 업무에도 꽤 민감한 문제였습니다.

1990년의 한국은 기업들이 종이 문서 기반 처리에서 전산화가 이루어지던 과도기였는데, 당장 MBC 내부 전산망에 MBC의 드라마 ‘똠방각하’의 제목을 못 써넣어 ‘돔방각하’라고 표기하는 경우도 발생했습니다.

이런 해프닝이 지속되면서 조합형과 완성형 인코딩의 팽팽하던 주도권의 균형이 무너진 시점은 윈도우95 등장 이후입니다. MS가 OS 차원에서 확장 완성형을 기본으로 지원하게 된 것이죠.

이 때 등장한 것이 MS의 CP949(코드 페이지 949) 입니다. CP949는 KS X 1001라는 완성형 인코딩 체계에 없는 한글 8822글자를 추가해서 EUCKR을 확장한 완성형 인코딩 방식으로, 128이상의 영역 중 EUCKR이 사용하지 않던 영역에 이 8822글자를 할당했습니다.

하지만 이 CP949도 문제점이 있었는데요, 기존의 완성형과 새로 추가된 글자가 사전순이 아니고, 심지어는 기존 완성형 사이에 정렬되어 있기 때문에 단순히 코드만을 가지고 사전 순서로 찾거나 정렬할 수 없었다는 것입니다.

UNICODE(유니코드)

이러한 혼동 속에서 ‘하나의 문자 집합’으로 전 세계 문자를 모두 표현하려는 움직임이 있었고, 썬마이크로시스템즈, 애플, MS, IBM 등의 회사들이 ‘유니코드 컨소시엄’을 만들어 전세계 문자를 통합한 유니코드(Unicode) 를 만들기 시작했습니다.

참여한 회사들을 보면 거의 미국 회사인 것을 알 수 있는데요, 미국 회사들이 전세계에 소프트웨어를 판매하다보니 통합의 필요성을 느꼈다는 것이겠죠?

그렇게 미국의 주도 하에 1991년 UNICODE 1.0이 탄생합니다.

유니코드의 기본 아이디어는 간단합니다. 세상의 존재하는 모든 글자를 다 모아 하나의 코드 체계로 표현하는 것입니다.

예를 들어 ‘A’는 65번, ‘가’는 0xAC00번, ‘が’는 0x304C번과 같이 번호를 부여하여 명칭 그대로 코드(Code)를 통일(Uni)한 것입니다.

유니코드가 포함하는 문자를 보면 우리가 흔히 아는 글자 외에도 도형, 이모티콘과 같은 것들도 포함이 되어있는데요, 컴퓨터로 표현 가능한 모든 문자를 코드화하는 것이 유니코드의 목표였습니다.

하지만 유니코드를 막상 쓰려고하자 문제가 발생합니다. 문자수가 너무 많기 때문에 한 바이트로 값을 저장할 수 없고 2바이트 이상을 사용해야한다는 점입니다.

최신 버전(16.0)으로 유니코드가 표현하는 글자 수는 154,998입니다. 2바이트로 표현할 수 있는 숫자가 총 65,535개이니 2바이트로도 부족하고 3바이트를 써야 모든 유니코드의 문자를 표현할 수 있습니다.

여기에는 두가지 문제점이 있습니다.

1. 바이트 순서(Byte order or Endian) 문제

한 데이터를 저장할 때 어떤 컴퓨터 시스템은 순서대로 저장을 하지만 어떤 컴퓨터 시스템은 역순으로 저장을 합니다.

예를 들어 “가”(0xAC00)를 어떤 컴퓨터 시스템은 0xAC00으로 저장하지만, 어떤 컴퓨터는 0x00AC로 저장합니다.

즉, “가”를 0xAC00으로 저장하는 컴퓨터에서 만든 문서를, “가”를 0x00AC로 저장하는 문서에서 읽으면 엉망이 됩니다.

이를 해결하기 위해 등장한 방법이 BOM(Byte Order Mark, 바이트 순서 표식) 입니다. 데이터가 시작하기 전에 문서의 맨 앞에 BOM(FE FF 또는 FF FE)을 먼저 저장하자는 방법입니다.

문서를 읽는 쪽에서는 앞에 2바이트를 먼저 읽고 나서 FE FF이면, 0xAC00을 “가”라고 해석하고, 앞에 2바이트가 FF FE였다면 0x00AC를 “가”라고 해석하게 됩니다.

2. 공간 낭비 문제

과거 ASCII 시절에는 1바이트면 “A”를 저장할 수 있었는데 이제는 “A”를 저장하기 위해서 3바이트를 써야합니다. 영어로만 된 문서는 모든 문서의 크기가 3배가 되어 손해겠지요.

한글도 마찬가지로 2바이트로 표현했었는데 3바이트를 써야합니다. 같은 정보를 저장하는데 1.5배의 공간이 필요합니다.

이 문제를 해결하기 위해서 Variable-length byte(가변 길이 바이트) 라는 아이디어가 등장합니다. 자주 쓰는 문자는 적은 바이트로 표현하고, 가끔 쓰는 문자는 많은 바이트로 표현하는 것입니다.

예를 들어 기존 ASCII 영역에 있는 영어 알파벳은 기존과 같이 1바이트(정확히는 7bit)를 써서 표현하고, 아랍 문자는 2바이트를, 베다어 글자는 3바이트로 표현하는 식입니다.

이렇게 하면 확률적으로 문서의 많은 부분은 적은 바이트를 사용하기 때문에 전체적으로 적은 공간으로 정보를 저장할 수 있습니다.

UTF(Unicode Transformation Format)

이 가변 길이 바이트 아이디어를 실체화한 인코딩 중 가장 대표적인 것이 UTF-8입니다. UTF-8의 규칙에 따르면:

0x000000 ~ 0x00007F는 0x1xxxxxx의 1바이트 (ASCII 동일)
0x000080 ~ 0x0007FF는 0x110xxxxx 10xxxxxx의 2바이트
0x008000 ~ 0x00FFFF는 0x1110xxxx 10xxxxxx 10xxxxxx의 3바이트

위와 같이 저장되며, x에 해당하는 부분이 실제 문자에 해당하는 코드가 나눠 저장되는 것입니다.

UTF-8으로 된 문서에도 BOM을 쓸 수는 있지만 실제로는 대부분 쓰지 않습니다. 몇가지 규칙을 이용해서 쉽게 문서의 Byte Order를 알 수 있기 때문입니다.

오히려 어떨 때는 BOM이 있고, 어떨 때는 BOM이 없어서 혼란을 주기 떄문에 UTF-8에 BOM을 쓰는 것을 금지해야한다는 주장도 있습니다.

UTF-8가 가지는 또다른 장점은 기존의 ASCII와 완벽히 호환된다는 점입니다.

앞의 설명처럼 0x00007F까지는 ASCII와 똑같은 코드를 사용하기 때문에 이 영역을 사용하는 문서(수많은 영어 문서, 프로그램 코드 등)는 ASCII 인코딩과 UTF-8 인코딩이 완전히 일치합니다.

즉, 과거의 수많은 ASCII 인코딩 기반 파일을 전혀 변환없이 사용할 수 있습니다.

현재 유니코드는 계속해서 새로운 문자를 추가하고 있습니다. 알파벳, 한글과 같은 전통적인 문자 개념을 넘어서 이모티콘과 같은 영역까지 포함하고 있기 때문이죠! 유니코드의 업데이트 내역은 유니코드 홈페이지에서 확인할 수 있습니다.

이렇게 유니코드는 다른 바이트를 사용해 유니코드를 UTF 인코딩 규칙이라는 해결법을 고안하여, 다른 국가의 사용자가 다른 언어로 된 문자를 동시에 영향을 받지 않고 읽을 수 있도록 하여 인터넷의 대중성을 크게 향상시키게 되었습니다.

맺음

문자 인코딩 기술의 발전 과정을 살펴보았습니다.

개인적으로 역사 공부하는 것을 좋아해서 어느 사실에 대한 기원을 쫓아가는 것을 좋아하는데, 개발 지식도 이렇게 접근하니 정리하는 데는 힘들었지만 글쓰면서 재밌었네요.

어느 사실, 정보에 대한 기원을 알아보는 Origin Series를 정기적으로 연재해보면 좋겠다는 생각이 듭니다.

읽어주셔서 감사하고, 피드백은 달게 받겠습니다.

출처