20090420 :: 모든 것에 대한 집합, 유니코드

이 글에 언급된 몇몇 내용은 부정확한 추측이라 보다 정확하게 정리한 글을 다시 작성하였습니다. 유니코드에 대한 개요는 이 글을 참고해주세요.

문자열이란 무엇일까요

파이썬으로 한글을 출력하는 프로그램을 만들어서 명령창에서 실행해보면,  한글이 죄다 깨어져 나오는 문제를 경험합니다.(물론, 조금만 신경쓰면 그럴 일은 없습니다) 또는 윈도에서 zip으로 압축한 파일을 리눅스에서 열어보면 또 역시나 한글 이름이 와장창 깨어져서 압축이 풀립니다. 멀리까지 갈 필요도 없이, 이름이 일본어로 되어있는 파일도 압축했다가 나중에 풀어보면 또 이름이 와장창 깨어져서 나오거나, 아예 압축이 풀리지 않는 불상사가 일어나기도 합니다. 이런 문제점들은 사실 인터넷이 없던 시절에는 경험하기 아주 힘든 문제였습니다. 왜냐면 사용자가 사용하는 언어가 다른 곳에 있는 두 컴퓨터가 서로 자료, 아니 문자열을 교환할 일은 매우 드물었기 때문입니다. 

이 글은 ‘유니코드는 무엇’이며, ‘UTF-8’은 무엇이고 또 ‘EUC-KR’은 무엇이냐에 대해 살짝 알아보기 시작하다가 한 없이 꼬여버린 생각들을 조금이나마 정리하고자 하는 의도로 작성되었습니다.

그들은 상상력이 부족했을까

처음 개인용 컴퓨터를 설계한 엔지니어들은 PC가 사용하는 메모리 영역의 최대값을 640KB로 제한했었습니다. 그보다 더 큰 규모의 메모리를 일반 사용자들이 사용할 일이 ‘결코’없을 것이라고 생각했었기 때문이지요. 그래서 도스를 많이 쓰던 시절에 게임 좀 했던 분들은 ‘중첩확장메모리’니 ‘연속확장메모리’니 하는 것들에 휘둘리면서 어렵게 어렵게 게임을 돌려보신 경험들이 있을 겁니다. (요즘의 도스 박스 같은 도스 에뮬레이터도 비슷한 문제가 있지 않나 싶습니다만, 거기까지 파고 들기에는 제 인생이 너무나 피곤하네요. 그냥 뭐 게임만 잘되면 장땡이지.)  아무튼 그 초기 엔지니어들을 탓하자는 건 아니고, 그 분들은 당연히 ‘문자열’에 대해서도 깊이 고려를 하지 않았습니다. 뭐 저라도, 세상이 놀랄만한 전자계산기를 만들고는 이걸 영어도 못 읽는 코찔찔이 (! 여기선 미국의 코찔찔이들을 말하는 겁니다. 비 영어권 사용자 역시도 생각을 못했을테니까요) 들이 사용하게 되리라는 걸 상상이나 했겠습니까.

아무튼 PC는 그들의 상상력을 단 몇 년 사이에 몇 번이나 깨부수고 말았습니다. 하기사 요즘 다들 하나씩 들고 다니는 휴대전화만 하더라도, XT/AT 등의 컴퓨터들과는 비교도 되지 않을만큼 고성능이 아니던가요.  어쨌거나 좋든 싫든 PC의 핵심 부품들과 제조 기술은 전 세계로 뻗어나갔고, 지금은 지구상의 일부 국가에는 매우 보편적인 ‘가전제품’으로서의 컴퓨터가 자리잡고 있는 실정입니다. 게다가 그 들 중 많은 컴퓨터들은 ‘인터넷’이라는 어마어마하게 복잡하게 얽히고 섥힌 네트워크에 물려서 서로 연결되어 있는 상황입니다.

아무튼 컴퓨터를 처음 만드신 분들이 썼던 언어는 ‘영어’였습니다. 당연히 문자열을 취급하기 위해서 지금과 같은 ‘문자집합’은 필요했겠지요. 하지만 문제가 되지 않았던 것이 이런 문자 집합을 표현하기 위해서는 단지 1바이트의 값이 필요했을 뿐이었습니다. (좀 더 정확히는 7비트) 영어 대소문자, 각종 특수 기호, 심지어는 사람이 읽는 ‘부호’가 아닌 외부 출력 장치를 제어하기 위한 제어문자등을 총 망라해도 128자 안에 다 들어갔었다는 말입니다. 그 당시의 고민은 그 많은 영역에 얼마나 많은 글자와 부호를 채워넣어야 할까가 더 고민되지 않았을까라고 생각해 봅니다.

바다를 건너간 컴퓨터

이제 PC가 바다를 건너 영어를 쓰지 않는 나라로 건너갔을 때의 상황을 살펴보겠습니다. 1980년대 후반, 우리 나라에서도 가정집에 PC라는 물건들이 침투하기 시작했습니다. 그 당시에 사무실 등지에서는 얼마나 PC를 활용했는지는 잘 모르겠습니다만, 모르긴 몰라도 왠만한 규모가 있는 업체라면 ‘PC실’ 정도는 갖추고 있었으리라고 믿어 의심치 않습니다. 그리고 화면에, 서류에 한글을 사용할 필요성이 있었겠지요. 그래서 우리 나라의 표준 기구에서도 ‘한글’을 표현할 문자 집합(character set)을 표준으로 제정하려 했습니다. 이 때 승부를 벌였던 두 후보가 바로 ‘완성형’과 ‘조합형’이었습니다. 결국 표준의 자리는 ‘완성형’이 차지하였고, 한글학계에 몸담으신 분들께서 이러한 상황을 비난하고 나서는 뭐 그런 일들이 있었습니다. 그리고 표준 제정 여부와는 무관하게 ‘우리 한글에 꼭 맞는’다며 조합형은 많은 사용자들의 지지를 받았었고, 그 대표적인 유산이 한글과 컴퓨터의 ‘한글 워드프로세서’입니다. 뭐, 여기까지는 많이 알려진 이야기이지요.

그런데 그 당시에 사용된 ‘완성형’이나 ‘조합형’ 문제 집합은 모두 2바이트 문자를 사용하고 있었습니다. 즉 하나의 문자를 나타내는 값에 16비트를 사용했다는 것이지요. 따라서 서로 다른 문자를 나타내는 값이 256개를 넘어도 괜찮았지요, 다만, 완성형은 ‘좀 귀찮았던 관계’로 사용 가능한 한글 글자 모양이 좀 심하게 적었습니다. 그렇다고해도 일상 생활에 크게 불편함을 초래할 수준은 아니었습니다.

아무튼 ‘똠방각하’도 못쓰는 ‘우스운’ 신세로 전락한 우리의 표준, 완성형 한글은 윈도95가 등장하면서 ‘확장완성형’이라는 이름으로 다시 태어납니다. 물론 기존의 완성형과의 ‘하위호환성’을 위해서 좀 순서가 뒤죽박죽으로 변하기는 했지만, 어쨌거나 조합형 한글 못지 않게 ‘온갖’ 한글을 쓸 수 있게 되었습니다. 물론 ‘더 비과학적으로’ 쑤셔 넣기에 바빴던 모양새라 출시되고 나서도 한 동안 ‘이 죽일 놈의 확장 완성형’ 취급을 받기도 했지요.

그리고 다음으로 이야기를 이어 나가기 전에 또 이런 생각을 잠깐 해봐야 하는 순간이 찾아옵니다.

한국 말고 또 바다를 더 건너간 컴퓨터

설마, 중국의 한자가 ‘천자문’에 나와있듯이 1,000자 밖에 안된다고 생각하시는 분은 없겠죠? 아무튼 중국에서도 나름대로 2바이트 문자 집합 체계를 정립하려고 애를 썼을 것이고, 그 내용은 잘 모르지만 중국 사람들도 컴퓨터를 잘 들 써왔을 것이기 때문에 역시나 65535자 제한 내에서도 큰 불편없이 한자를 사용했을 겁니다. 그리고 일본에서도 ‘가나’ 문자 외에도 한자를 많이 쓸 것이니 역시 2바이트 문자 집합을 사용하고 있었겠지요. 그런데 슬슬 ‘인터넷’이 생기고 이제 한 컴퓨터에서 다른 언어 문화권으로 ‘문서’를 전송하다보니 문제가 생기기 시작합니다. 예를 들어 일본에서 한국으로 일본어로 된 문서를 전달하려니 기가 차는 노릇이지요.  왜냐면 맨 처음부터 127번째 문자 이후의 영역, 그러니까 최초에 정의된 영문자 및 기호문자들의 영역을 제외한 그 이후 영역은 나라 별로 각자의 표준을 사용하여 글자를 지정하다보니, 보낼 때는 일본어로 보낸 문자열이 여기서는 괴상한 한글로 보이기 시작하더라는 말입니다. 아니, 문득 정신을 차리고보니 전세계의 거의 모든 나라가 자신들만의 문자를 갖고 있는데다가 (많은 경우, 영어 알파벳과 비슷하게 생기긴하였습니다만) 1바이트든 2바이트든 정리된 듯한 그 ‘표준’들을 한 데 모아 놓고 보니 너무나 뒤죽 박죽으로 엉켜있는 형상이더란 말입니다. 

결국 2바이트 문자열 집합으로 어느 수준까지 한 언어에서 사용하는 문자만 취급하는 것은 어느 정도 불편함이 없겠습니다만, 서로 다른 언어들을 생각하면 머리가 아파오기 시작하는 것이었죠. 여기서 다시 고백하노라면 아니 보다 정확한 사실을 말씀드리자면, 사실 완성형 한글은 고작 2350자 밖에 표현하지 못했습니다. 어찌보면 말도 안되는 것 같지만 그 때는 정말 그것만 갖고도 큰 불편함 없이 잘 썼었습니다!

상황이 이렇게 되자, 아니 잘은 모르겠지만 상황이 그렇게 되기 조금 전부터 선견지명이 있던 분들로부터 시작하여, ‘아 골치아파 그냥 모조리 한 데 다 때려박자’는 움직임이 일기 시작합니다. (왠지 선견지명 있으신 분들과는 조금 거리가 있어 보입니다…) 그리하여 전세계 소프트웨어 업체며, 표준 기구 등등 많은 머리 좋은 분들이 연구하고 협의한 끝에 ‘유니코드’라는 것을 만들어 내었습니다. 빠밤~ 말 그대로 ‘유니코드’, 하나만 있으면 되는 문자 집합이었던 것입니다.

유니코드의 탄생

그리하여 유니코드가 제정되었습니다. 전체 문자 집합은 몇 개의 언어 그룹으로 나누고, 개별 그룹은 다시 몇 개의 언어판으로 나뉘며, 각 언어판은 65535자를 수용할 수 있도록 만들었습니다. 자세한 기술적인 사항은 이곳(진숙의 유니코드 입문서)을 참조하시면 되겠습니다. (저도 기술적인 내용은 잘 모르겠습니다.) 이제는 그야말로 ‘인터네셔널’한 프로그램을 만드는 것이 가능해졌습니다. 이렇게 해서 지금까지는 유니코드가 어떻게 만들어졌나 하는 부분을 살펴보았습니다. 하지만 정작 헷갈리는 것은 그럼 UTF-8 이니 혹은 UTF-16이니 하는 것과 EUC-KR은, 또 CP-949는 어떻게 다르냐는 것이지요. 네 그렇습니다. 그러니까 UTF-8은 유니코드입니다. 하지만 UTF-16 이라는 것도 있습니다. 이것도 유니코드입니다. 가장 황당한 것은 메모장에서 텍스트 파일의 저장 형식을 보면, UTF-8과 ‘유니코드’가 또 따로 있다는 겁니다. 가만, 그럼 EUC-KR은 유니코드인가요? 아닌가요? 무지하게 헷갈립니다. 조엘 아저씨의 ‘일반 텍스트는 없다’는 이야기를 읽고 나서는 더더욱 헷갈리기 시작합니다. 파이썬에서는 EUC-KR로 작성한 텍스트 파일을 읽어 들여서 s.decode(‘euc-kr’).encode(‘utf-8’)이렇게 UTF-8로 바꿔서도 쓰는데, 그럼 디코딩되었다가 인코딩 되기 직전에 그 데이터가 ‘일반텍스트’에 해당하는 것이 되어야 하는 건 아닌가 하는 생각도 듭니다. 

문자열도 ‘인코딩’된다

그래서 뒤지고 뒤지다보니 UTF-8이니 하는 것은 유니코드 문자열을 저장하기 위해 ‘인코딩’하는 방법의 하나라는 것을 알게되었습니다. 이건 또 뭐래요? 그러니까 우리가 메모장에서 ‘가’라는 글자를 만들고 이걸 그냥 유니코드로 저장하면 FF FE 00 AC 따위로 저장되는데, 이건 그냥 순수한 유니코드의 문자열 코드 값인 거고 이를 UTF-8로 인코딩하면 EA B0 80이 됩니다. 이렇게 인코딩 하는 방법 중 하나가 EUC-KR이고 또 UTF-16이고 뭐 그렇다는 겁니다. 그렇지만 EUC-KR은 유니코드 인코딩은 아니고 그냥 완성형 한글을 인코딩하는 규칙이라고 생각하면 됩니다. 결국 ‘없는 줄 알았던’ 원래 진짜 문자를 나타내는 값은 존재했던 겁니다. 그게 바로 유니코드(물론 유니코드로 작성해서 유니코드로 저장하는 문자열인 경우에)였고, 이를 저장하는 방식이 UTF-8 등의 인코딩 방식이었던 것이죠.  그리고 하나 재미있는 것은 UTF-8에서 한글 한 글자는 3바이트로 쪼개집니다. 그러니까 영문은 1바이트, 한글은 2바이트… 이런 식으로 나누는 것은 무관하다고 봐도 좋겠네요. 이제야 조금 실마리가 풀리는 느낌이었습니다. 그래서 파이썬 예전 버전을 설치하면서 한글을 사용하는 경우에는 ‘코덱’을 같이 설치해야한다는 이야기가 나왔던 것이었군요. (그 전에는 몰랐습니다. 동영상도, 음악파일도 아닌 한글을 쓰자고 코덱을 설치한다라고?) 그리고 또 깨달았습니다. 무엇으로 만들어졌는가를 알기 이전에는 조엘 아저씨말대로 ‘그냥 문자열’이라는 건 존재할 수 없다는 것도 이해가 됩니다. 

결론

아무튼 긴 시간 동안 유니코드가 무엇일까라는 질문에 스스로 답하기 위해 많은 시간을 들여 깊고도 넓은 정보의 바다를 헤매고 다녔고, 또 어느새 월요일 아침이 밝아옵니다. 이제 씻고 제 정신을 차린 다음, 출근을 하러 나가야겠군요. 그러니까 이렇게 긴 학구적 방황 끝에 내린 결론은 다름 아닌 다음과 같습니다.

그냥 개발자 아니면 어렵게 생각하지 말고 ‘UTF-8’로 웹 문서 만들자

네, 그렇습니다. 그런 거지요 뭘. 횡설 수설하는 긴 글 읽어주셔서 감사합니다.

 

참고 사이트