아스키코드와 유니코드

컴퓨터와 사람의 의사소통

컴퓨터는 어떻게 자료를 표현할까? 컴푸터가 정보를 표현하기 위한 기본 원리는 전기신호이다. 전기신호가 있으면 ‘1’, 없으면 ‘0’ 두 가지 경우로 정보를 표현한다. 이 ‘0’과 ‘1’을 데이터의 최소 단위라고 하고 비트(bit)라고 부른다.

그런데 이 하나의 비트는 0과 1만 표현할 수 있기 때문에 우리가 사용하는 문자를 표현하기에는 크기가 너무 작다. 그래서 바이트(byte)라는 단위를 사용하게 된다.

바이트란, 일정한 개수의 비트로 이루어진 연속된 비트열이다. 여기서 ‘일정한 개수’가 항상 정해진 건 아니지만, 최근에는 1바이트를 8비트로 간주하는 경우가 흔하다.

한 개의 비트는 0과 1, 2개의 정보를 표현할 수 있는데 이것을 8개로 묶으면 2^8개, 즉 256가지의 정보를 표현할 수 있다. 따라서 숫자와 영문자를 모두 표현할 수 있고 남는 공간에 특수문자까지 할당할 수 있다.

비트와 바이트의 개념을 알았으니 이제 본격적으로 아스키코드와 유니코드에 대해서 알아보자.

아스키코드(ASCII)

아스키코드의 등장 이유

앞서 설명했듯이 컴퓨터는 우리가 말하는 a,b,c를 알지 못한다. 그래서, ‘(예를 들어)a는 1이고 b는 2다’ 라는 것을 미리 기기에 입력해두어야 한다.
그런데 여기서 문제가 발생한다. 어떠한 기준이 없기 때문에 어떤 기기는 a를 2라고 표현하고 어떤 기기는 a를 1이라고 표현하게 되면서 글자가 와장창 깨지게 된다.
따라서 숫자와 문자를 매칭시키는 국제적인 규칙을 만들게 된다.
이 규칙을 아스키코드라고 한다.

아스키코드의 문자표

여기서 문자표란? 숫자와 문자를 1대1로 매칭시킨 표를 말한다.
영어로 CharacterSet이라고 한다. html에서 사용한 그 charset이다.

아스키코드는 1바이트, 즉 8비트의 데이터를 사용한다.
아래 표를 참고해서 a는 어떻게 변환되는지 알아보자.
아스키코드표

표를 참고하면 a는 이진수 100 0001로 변환된다. 그런데 여기서 이상한 점이 있다. 아스키코드는 8비트의 데이터를 사용한다고 했는데 표의 이진수는 일곱자리다. 그러면 한자리는 어디갔을까?

이 한자리는 패리티 비트(parity bit)라고 부르는데, 데이터의 에러를 탐지하기 위해 사용한다. 일곱자리의 이진수에서 ‘1’이 홀수개라면 끝에 1을, ‘1’이 짝수개라면 끝에 0을 덧붙인다. 아주 정밀하진 않지만 패리티 비트를 이용해 어느 정도의 에러를 탐지할 수 있다.

따라서, 패리티 비트를 제외하면 아스키 코드는 총 7자리의 이진수를 문자로 내타낼 수 있기 때문에 총 2^7개인 128개의 문자를 나타낼 수 있다.

아스키코드의 문제점

아스키코드(ASCII)에서 A는 american이다. 즉, 아스키코드표에는 영어만 존재한다.
아스키코드표가 만들어질땐, 영어권 사람들만 주로 컴퓨터를 이용했는데 시간이 지나면서 여러 나라에서 컴퓨터를 사용하게 되면서 다양한 표준들이 생기게 된다.
이렇게 다양한 표준들이 충돌하고 문자가 깨지면서 ‘걁궬뷀뒐’ 같은 문자가 표현됐다.

따라서, 이 많은 표준들을 하나로 합칠 새로운 기준이 필요해졌다.

유니코드(Unicode)

아스키코드로는 모든 언어를 표현하는데 한계가 있었고 전 세계 언어의 문자를 정의하기 위한 국제 표준 코드가 등장하였다.
바로 유니코드이다. 1바이트로는 부족했으니 용량을 크게 확장한 2바이트(2^16 = 65,536)를 사용하게 된다.

처음에는 65,536개에 온 세상 문자를 모두 담을 수 있을 것이라 생각했지만 쓰지 않는 고어, 토속어 같은 모든 문자를 담으려다 보니 이마저도 부족했다. 이를 해결하기 위해 약 백만자가 넘는 문자를 추가로 정의했다.

유니코드의 문제점

그런데 이 유니코드에서 문제점이 발생한다.
유니코드가 영어를 표현할 땐 1바이트로, 한글을 표현할 땐 2바이트로, 다른 특수문자를 표현할 땐 3바이트로 표현하는 가변적인 표현의 문제가 생긴다.
어쩔 땐 1바이트를 읽고 어쩔 떈 2바이트를 읽으니 이는 컴퓨터에게 매우 큰 혼란은 준다. 따라서 어떤 글자는 1바이트로, 어떤 글자는 2바이트로 읽을지 정해줘야한다.

유니코드 인코딩 방식

앞서 나온 문제점을 보완하기 위해 유니코드에는 다양한 인코딩 방식이 존재한다.
인코딩 방식이란, 컴퓨터가 어떤 글자를 만났을 때 얼만큼씩 읽어야 하는지 미리 말해주는 것이다.
유니코드의 인코딩 방식으로는 코드 포인트를 코드화한 UCS-2와 UCS-4, 변환 인코딩 형식인 UTF-7, UTF-8, UTF-16, UTF-32 인코딩 등이 있다.

UTF-8(8-bit Unicode Transformation Format)

다양한 유니코드 인코딩 방식 중 우리에게 익숙한 UTF-8 방식을 살펴보자.
UTF-8은 문자열 집합과 인코딩 형태를 8비트 단위로 한다는 의미를 가지고 있다.

유니코드 한 문자를 나타내기 위해서 1바이트에서 4바이트까지 사용한다. 이를 가변 길이 인코딩 방식이라고 한다.
왜 가변적으로 인코딩할까? 그냥 일정하게 4바이트씩 읽어들이면 더 편하지 않을까?
아스키문자들은 1바이트로 하나의 문자를 표현할 수 있는데 모든 문자를 4바이트를 사용한다면 지나친 저장소의 낭비가 된다.
따라서 아스키코드로 표현 가능한 것들은 1바이트로 표현하고 그것이 안된다면 2바이트 이상을 사용하는 방식이 UTF-8 방식이다.

그렇다면 어떻게 1바이트로 읽을지 4바이트로 읽을지 알 수 있는걸까?
그것은 첫번째 바이트를 시작하는 비트가 어떤 것이냐를 보면 알 수 있다.

0xxxxxxx : 첫 번째 바이트가 0으로 시작한다면 0이외의 7 비트를 아스키로 인식한다.
110xxxxx 10xxxxxx 두번째 바이트까지 읽어서 하나의 문자로 표현
1110xxxx 10xxxxxx 10xxxxxx 세번째 바이트까지 읽어서 하나의 문자로 표현
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 네번째 바이트까지 읽어서 하나의 문자로 표현

여기서 UTF-8의 강점은 아스키방식과 완벽하게 호환된다는 것이다.
최근에 표준으로 가장 많이 사용되고 있는 인코딩 방식이다.

왜 한글이 깨질까?

여기서부터는 추가적인 개념이다.
우리가 겪는 한글이 깨지는 현상의 이유가 뭘까? 다양한 이유가 있겠지만 거의 대부분 이것의 문제이다.
EUC-KR로 인코딩이 된 것을 UTF-8로 읽거나, UTF-8로 인코딩 된것을 EUC-KR로 읽어들일 때 한글이 꺠지는 경우가 가장 많다.

charset이 유니코드도 있지만 유니코드 이전에 한글을 표현하기 위한 KS X 1001이라는 문자표가 존재했다.
이 문자표를 택한 곳이 바로 마이크로소프트이다. 마이크로소프트사에서 윈도우를 개발할 때 이 문자표를 표준으로 선택했고 이 문자표를 인코딩한게 바로 EUC-KR이다.

그렇기 때문에 애초에 EUC-KR과 UTF-8은 문자표도 다르지만 인코딩 방식도 달라 당연히 깨질 수 밖에 없는 것이다. 우리는 한글 윈도우를 사용하고 웹에서는 UTF-8을 사용하기 때문에 웹 프로그래머는 UTF-8로 인코딩을 별도로 해줘야 한다.