컴퓨터 지식 공부/기타

<22.02.23> 컴퓨터 지식 공부 일지 #02. 인코딩에 대해 - ASCII? Unicode? UTF-8?

mayberry 2022. 2. 23. 21:25

 프로그래밍을 하다가 파일 입출력 함수를 통해 csv 파일로 내보내거나 txt 파일로 내보내는 경우가 있다. 이후 파일을 열면 기괴발랄한 문자들이 등장할 때가 있다. 잘 몰랐을 때는 그냥 대충 구글링해서 인코딩 관련 구문을 추가하여 문제를 해결한 적이 많았었는데, 이제는 그러면 안되겠다는 생각이 들어 유튜브나 위키에서 찾아본 것을 정리하여 포스팅하기로 했다. 

 

인코딩이란 존재를 처음 마주했을 때 느낀 것.. 뭐지 이건

 

 우선 인코딩이란 무엇일까? 사람이 사용하는 문자를 컴퓨터가 이해할 수 있게 변환하는 것이다. 일종의 번역인셈. 그 반대의 경우는 디코딩이라고 한다. 포스팅 내용에서 다룰 인코딩 역시 이러한 개념에 속한 것으로, 문자열 인코딩에 대해 알아보고자 한다. 

 

 초기에 개발된 컴퓨터는 수학적 계산만을 진행해도 무리가 없었다. 하지만 컴퓨터가 계산한 결과를 인간이 받아보기 위해서는 결국 적절한 형태의 문자로 출력해야했다. 하지만 컴퓨터는 1과 0이라는 데이터만 인식하기 때문에 기존에 개발했던 컴퓨터로는 ? / = 과 같은 문자열은 출력할 수가 없었다. 그래서 이 문제를 해결하기 위해 '문자표(Character Set)'ㅡ문자열 세트가 정식용어인것 같으나 편의를 위해 본 포스팅에서는 문자표라고 표현한다ㅡ을 개발한다. 

 

1. 문자표(Character Set)란?

   컴퓨터가 인간의 문자를 이해하기 위해 만들어진 하나의 표(table)이다. 즉, 각 문자에 고유한 숫자들이 매핑되는데, 이렇게 매핑되어 작성된 표다. 예를 들면 '?'는 0 '!'는 1, 'A'는 13 이런식으로.. 아래 그림을 보면 이해가 쉽다.

 

1972년 프린터 사용 설명서에 첨부된 아스키 코드 차트표

컴퓨터는 이렇게 제작된 문자열 세트를 통해 인간이 입력한 문자열을 위와 같은 문자표를 보고 이해한다. 컴퓨터가 수행한 연산결과를 인간에게 보여주기 위해 문자표를 보고 그에 해당하는 문자열을 찾아 출력한다. 이러한 방법으로 인간이 읽을 수 있는 문자를 컴퓨터에 전송하고, 컴퓨터를 통해 읽을 수 있게 되었다. 하지만 아래와 같은 문제가 발생한다.

 

부산 대신동에 있는 A회사의 컴퓨터는 '가'가 1이고 '나'가 2인 문자표를 가지고 있다고 하자. 개발자 Q는 A 회사에서 사용하던 컴퓨터로 계산한 자료를, 서울 가리봉동에 있는 B회사로 가져갔다. Q씨는 부산에서 가져온 자료를 B회사의 컴퓨터에 입력하니 이상한 결과가 나왔다! 서울 가리봉동에 있는 B회사의 컴퓨터는 '가'가 100이고 '나'가 200이었던 문자표로 계산하고 있었기 때문이다!

 

 문자표를 만들어서 컴퓨터에게 인간이 사용하는 문자열을 이해시키는 데까진 문제를 해결했지만, 모든 컴퓨터들이 공통된 문자표를 가지고 있지는 않았다. 그래서 서로 다른 컴퓨터끼리는 같은 값을 가지더라도 서로 다른 결과물을 출력하게 되었다. 이러한 문제를 해결하기 위해, 미국 표준 협회(ASA)가 주도한 X3 위원회가 공용 문자표인 '미국정보교환표준부호(American Standard Code for Information Interchange)', 그 이름도 유명한 'ASCII'를 고안한다.  

 

2. ASCII

 

아스키 코드표

 

 ASCII 코드의 초판이 발간되었던 때가 1963년이었는데, 한국에서 최초로 도입된 컴퓨터는 1967년 4월 경제기획원 조사통계국에서 도입한 IBM 1401이었다.ㅡ하지만 동년 3월 25일에 파콤222가 IBM보다 한 달 일찍 도착했지만, 통관 허가가 떨어진 날짜는 IBM 1401쪽이 빨랐다.ㅡ 이를 생각하면 미국에서는 범용 문자표가 초판으로 발간되고도 한번 더 개정했던 시기(1967년)에 한국에서는 컴퓨터가 최초로 도입되었다. 아마 ASCII 코드의 한계가 드러난 것이 1980년대 즈음부터가 아니었을까 생각해본다.

 

ASCII 코드는 7비트로 이루어져 있었다. 즉 1 Byte이내에 알파벳(대소문자 포함)을 포함한 제어 문자(지금은 사용되지 않는다고 한다)와 기타 특수문자를 포함하여 도합 128개의 문자를 표현할 수 있었다. 고안된 당시에는 모든 컴퓨터에 적용되었기에 미국 내에서는 편리하게 사용하였으나, 컴퓨터가 세계 각국에 보급되고 인터넷의 발전으로 다른 나라의 인터넷에도 접속이 가능해지던 때부터 ASCII 코드의 한계점이 발생한다. ㅡ인터넷에 대한 연구는 1960 ~ 1970년 미국국방부에서 시작하여, 민간에 배포된 것이 1980년 말이었다. ASCII 코드의 한계를 지적하며 이를 극복하기 위해 고안한 Unicode가 1987년에 등장한 것을 보면, 인터넷의 발달이 ASCII 코드의 한계를 드러나게 한 요인이 아니었을까라고 개인적으로 생각해본다.ㅡ

 

ASCII는 이름에서부터 'American'이 들어간다. 이는 철저히 '미국의, 미국에 의한, 미국을 위한' 문자표이다. 알파벳을 사용하지 않는 비영어권 국가(동아시아 및 유럽권)들에게는 ASCII를 따르지 않고, 자신들만의 범용 문자열을 개발해야 했다. 이후 인터넷이 발달함에 따라 외국의 사이트에 접근이 가능해짐으로써 서로가 사용하고 있는 문자표가 다르니, 웹 사이트의 글자들이 깨지는 오류가 발생한다. 이러한 문제를 해결하기 위해 조 베커(제록스)와 리 콜린스(애플), 마크 데이비스가 통일된 문자 집합을 만드는 것을 연구하기 시작했는데, 결과물이 바로 그 유명한 'Unicode'이다.

 

3. Unicode

 

Unicode의 다국어 기본 평면 표

 

Unicode는 ASCII로는 턱없이 부족한 표현력을 보강하는 수준에 그치는 것이 아니라, 전세계에서 사용하는 모든 문자열을 포함시켜 전세계 범용 문자표라고 해도 무방하다. 다국어 환경에서 지원하지 않던 ASCII의 한계를 극복하고도 그 이상의 것을 해낸 것이다.

 

Unicode는 1에서 4Byte 정도의 크기를 가지고 문자를 표현한다. 가변적으로 길이가 변화하여 문자를 표현한다. 1Byte로 표현가능한 문자열과 2Byte로 표현가능한 문자열도 있는데, 컴퓨터 입장에서는 이러한 방식에 혼란을 불러 일으킨다. 예를 들어 1Byte로 표현가능한 문자열을 사용하는 국가에서 ASCII 코드의 한계를 보완하기 위해 Unicode 인코딩을 사용한다치면, 가변 길이 인코딩 방식인 Unicode는 1Byte만 사용해도 되는데 불필요하게 2~3Byte 메모리를 점유하게 되어버리니 비효율적인 상황이 발생한다. 1~4Byte 정도의 메모리에 세상 모든 언어의 문자열을 집어 넣었으니 발생하는 문제점이다.

 

4. UTF-8

 

Unicode의 문제점을 해결하기 위해 켄 톰슨과 롭 파이크가 전두지휘하여 UTF-8(Universal Coded Character Set + Transformation Format - 8bit)를 고안한다. 이는 메모리의 크기에 따라 컴퓨터가 유동적으로 해석할 수 있도록 도와줌으로써 Unicode의 문제점을 해결했다. 여태까지는 기존의 문자표를 극복하기 위해 새롭게 고안된 문자표를 소개한 것이여서, UTF-8도 Unicode를 대체하기 위한 또 다른 문자표인가 싶을 수도 있으나, UTF-8은 Unicode를 인코딩하는 새로운 방법이다. UTF-8을 새로운 문자표라고 생각하면 안된다.ㅡ사실 내가 그랬다. 나는 바보다. ㅎㅎㅡ 

 

UTF-8은 Unicode 문자를 표현하기 위해 1Byte에서 4Byte까지 사용한다. UTF-8은 Unicode 내에서도 1Byte로 표현 가능한 경우와, 그 이상의 메모리를 점유해야 표현할 수 있는 상황에 대해서도 유동적으로 인코딩한다. 이를 쉽게 이해하기 위해 Unicode에서 채용하고 있는 '평면구조'에 대한 설명을 조금 하고자 한다.

 

Unicode는 '평면'이라는 구조를 가지고 있다. 이는 Unicode 전체를 논리적으로 나눈 구획을 의미하는데, Unicode는 0번부터 16번까지 총 17개의 평면을 보유하고 있지만, 4번 평면부터 13번 평면에는 어떤 문자나 기호도 배정되지 않은 상태ㅡ2015년 기준ㅡ이며 15번과 16번은 사용자 영역 평면으로 Custom 느낌이 강하다. 실제로 주요하게 쓰이는 평면은, 다섯개 정도다. 다국어를 표현하기 위한 평면(다국어 기본 평면)과 옛 문자나 음악, 수학 기호(다국어 보충 평면) 등등 다양한 평면 구조를 이루고 있다.

 

Unicode는 다국어 기본 평면 중 ASCII를 포함하고 있는 범위(U+0000 ~ U+007F)를 제외하고는 2Byte 이상의 메모리를 점유하게 된다. 이 때 UTF-8은 메모리 크기에 따라 특정한 표시를 통해 컴퓨터가 혼란을 야기하지 않고 해석할 수 있게 도와준다. 2Byte로 표현해야 하는 문자열의 경우는, 110xxxxx 10xxxxxx과 같이, 3Byte로 표현해야 하는 문자열의 경우는, 1110xxxx 10xxxxxx 10xxxxxx과 같이 표현한다. 

 

0xxxxxxx 0을 제외한 7bit를 하나의 문자로 표현(ASCII)
110xxxxx 10xxxxxx 두번째 Byte까지 읽어 하나의 문자로 표현
1110xxxx 10xxxxxx 10xxxxxx 세번째 Byte까지 읽어 하나의 문자로 표현
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 네번째 Byte까지 읽어 하나의 문자로 표현

 

눈치가 빠른 사람들은 첫 Byte의 상위 비트에 위치한 '1'의 개수에 따라 Byte의 길이가 결정됨을 알았을 것이다. 그리고 하위 Byte들의 상위 비트에는 항상 10으로 고정이다. 

 

위와 같이 표현하게 되면, Unicode 평면 중 1Byte로 표현하는 문자는 극히 일부에 불과하며, 2Byte로 표현하는 문자는 1920개 정도, 그리고 BMP(다국어 기본 평면)에 위치한 문자는 3Byte로 표현된다. 나머지 평면은 모두 4Byte로 표현할 수 있다. 위 표를 예시로 하여 UTF-8로 인코딩되는 원리를 설명하자면 아래와 같다.

 

U+C704라는 Unicode를 UTF-8 형식으로 변환을 하면, 해당 문자는 U+0800 부터 U+FFFF 영역에 있기 때문에 BMP에 속한다고 볼 수 있다. 3Byte로 표현된다는 의미다. 그렇다면 1110xxxx 10xxxxxx 10xxxxxx 과 같은 형태로 인코딩이 되는데, C704를 이진수로 바꾼 결과가 x에 대입되는 것이다. C704는 1100-0111-0000-0100인데 이를 1110xxxx 10xxxxxx 10xxxxxx에 대입하면 '11101100 10011100 10000100'이 되는 것이다.

 

즉 UTF-8은 Byte마다 배정된 상위 비트들을 통해 몇 Byte를 읽어야 하는지를 도와주는 인코딩 방식이라고 할 수 있다.

 

 

본 포스팅을 통해 인코딩에 대해 어느정도 감을 잡았으나 Unicode 부분을 아직 제대로 이해하지 못했다는 느낌이 든다. 향후 기회가 된다면 Unicode 부분만을 따로 공부하여 다시 포스팅하고 싶다. 이렇게 길게 작성할 계획이 아니었는데 쓰다보니 이렇게 되었다..  다음에도 다른 공부거리를 들고 포스팅하도록 하겠다.

 

P.S P. S 조잡한 글 읽어주셔서 감사합니다! 혹시나 틀린 정보가 있다면 과감한 지적(하지만 욕은 삼가해주시면 감사하겠습니다 ㅎㅎ) 부탁드립니다.