Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

c언어를 공부하다 보면 문자를 표현할때 한번쯤을 들어본 말이 있을 것이다. 복잡한 표에 십진수 표현과 문자형 표현이 쓰여져 있고, 우리는 분명 65라는 숫자를 출력했다고 생각했는데 이상하게도 'A'가 출력되는 진풍경을 맞닥뜨리게 된다. 이것을 '아스키 코드'라고도 얘기하는 것을 구글링을 하다 보면 알게되지만, 아스키 코드가 무엇인지 왜 이렇게 사용하는지 잘 알기는 쉽지 않다. 나 역시도 대략적으로 이 개념에 대해서 알고 있었고, 그래서 한번 정리를 해보고 넘어가고자 한다.

이진법으로 표현하기

초기에는 컴퓨터에서 문자를 표현하는 대표적인 방식이 'ASCII 인코딩 방식'으로 1바이트(8비트_bit)에 모든 문자를 표현했다. 우리는 이런 말을 들어본적 있다.

컴퓨터는 이진법으로 값을 표현한다.

여기서 이진법을 표현하는 최소의 단위가 1bit라고 생각하면 이해하기 쉽다. 하나의 비트에 0또는 1의 값으로 표현이 될 수 있으므로 하나의 비트는 총 두개의 의미를 표현할 수 있다. 그렇다면 8개의 비트는 2^8개의 표현을 가진다는 것을 알 수 있을 것이다.

아스키코드는 128개만 표현할 수 있었다.

그렇다면 왜 초기의 문자 표현을 얘기하다가 이진법에 대해서 언급을 했을까? 초기의 문자 표현은 '아스키 인코딩 방식'을 사용했고, '아스키 코드'는 8비트까지만을 표현할 수 있었다. 그러므로 우리는 유추할 수있다. 8비트라면 2^8개의 표현, 많이 해봤자 256개의 표현을 할 수 있었을 것이다. 이 개수는 많아보이지만, 실제로는 터무니 없이 부족하다. (한글만 생각해도, 자음과 모음의 조합이 11172자라고 하니,,당연히 부족하지) 심지어는 한개의 비트는 '체크섬'으로 제외하여, 실제로 어떤 값을 표현하는 용도보다는 통신 에러를 감지하기 위한 비트(패리티 비트)로 사용되었다. 결국 128개만 표현 가능했다. (한글이나 한자와 같은 문자는 2개 이상의 특수 문자를 합쳐서 표현하곤 했다.= "MBCS"(Multi-Byte Character Set) 이 경우, 깨지거나 제대로 표현되지 않는 경우가 잦았다)

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

이로 인해 등장한 것이 이름도 친근한 '유니코드'이다. 유니 코드는 전세계의 모든 문자를 컴퓨터에서 일관되게 표현하기 위해서 더 많은 바이트(2~4 바이트)를 사용해서 표현한다.

여기에서 2~4바이트라고 얘기하는 이유는 어떤 것은 2바이트, 어떤것은 4바이트와 같이 문자에 따라서 다른 바이트만큼 차지하기 때문이다. 이것은 어떤 문자인가에 따라서 길이가 다른 바이트를 사용하기 때문에 '가변길이 인코딩 방식'이라고 불리우며, 길이를 고정해서 표현하는 방법에 비해 메모리를 적게 차지하게 된다.
그중에서 가장 유명한 인코딩 방식인 utf-8에 대해서 알아보자.

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

utf-8의 경우 어떤 문자가 1바이트로 표현해야 하는지 2바이트로 표현하는지와 같이 그 길이에 따라서 맨앞비트를 다르게 표현한다.

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

(출처 : 파이썬알고리즘인텨뷰, 저 박상길)

이 표는 utf-8 바이트 순서에 따라 이진 포맷이 어떻게 달라지는 지 알려준다. 예를 들어, 'a' 라는 문자가 있다고 생각해보자.

'A'의 표현?

'A' 는 16bit(2byte)로 표시했을 때 다음과 같이 표시할 수 있다.

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

(출처 : 파이썬알고리즘인텨뷰, 저 박상길)

이경우 앞의 1byte는 0으로 채워져 있고, 우리는 뒤에 1byte만으로 'A'라는 문자를 차지할 수 있다. 실제로 'A'는 아스키 문자이므로 7비트 내에 표현이 가능하다. 그렇다면 utf-8에서는 이렇게 1byte만으로 표현하는 방식을 선택한다.

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

여기서 앞의 0은 위에 있는 이진 포맷상에서 1바이트만을 사용한다는 것을 알려주기 위한 약속이다.

이제 한가지 더 예시를 통해서 확실히 이해해보자.

'한'의 표현?

'한'이라는 글자는 확실하게 아스키문자가 아니다. 이것을 16bit로 표현한다면 다음과 같다.

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

(출처 : 파이썬알고리즘인텨뷰, 저 박상길)

'한'의 경우 16비트를 모두 사용해서 표현하게 된다. 2byte로 표현하기 위해서는 첫번째 바이트에 자리를 표현하는 비트인 3개(110xxxxx) 를 제외하고 5bit, 두번째 바이트에 자리를 표현하는 비트인 2개(10xxxxxx)를 제외하고 6bit, 총 11bit 이하로 표현이 가능해야 한다. 그러나 문자 '한'은 그 이상이기 때문에 3byte를 사용해서 표현해야한다.

3byte를 사용해서 표현할때는 첫번째 바이트에 자리를 표현하는 비트인 4개의 비트(1110xxxx)를 제외하고 4개의 비트, 두번째 바이트에 자리를 표현하는 비트인 2개의 비트(10xxxxxx)를 제외하고 6개의 비트, 세번째 바이트에 자리를 표현하는 비트인 2개의 비트(10xxxxxx)를 제외하고 6개의 비트 총 4+6+6 = 16개의 비트를 사용해서 표현이 가능하다. 이를 고려하면 다음과 같이 표현이 가능함을 알 수 있다.

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

(출처 : 파이썬알고리즘인텨뷰, 저 박상길)

단점

이렇게 메모리를 절약할 수 있는 utf-8방식의 인코딩은 아쉽게도 단점이 있다. 문자마다 차지하는 길이가 다르기 때문에 인덱스(들어가 있는 번호?라고 생각하면 쉬울 것 같다)를 통해서 접근하기가 어렵다.

파이썬을 예로 들어보자. 파이썬은 문자열 슬라이싱을 통해서 문자열관련 연산속도를 획기적으로 앞당겨준다. (ex: 문자열 뒤집기)
그런데 만약 문자마다 어떤것은 1byte, 어떤것은 2byte를 차지하는등 그 길이가 다르다면 어디비트에서 다른 문자로 바뀌는지 알기가 어렵고, 접근이 어려울 것이다. 이경우, 전체 문자열을 스캔해서 어떤 문자가 시작하는 위치를 따로 표시하는등의 다른 작업이 필요할 수 있다. 따라서 파이썬의 경우는 '고정 길이 인코딩 방식'을 사용해서 문자열 단위로 다른 고정 길이 인코딩 방식을 적용한다.(대부분의 경우 고정 2바이트 인코딩인 UCS-2를 사용한다)
[case1 : 모든 문자열이 ASCII 범위 내에 있다면? Latin-1 인코딩(고정 1바이트 인코딩)을 사용한다. case2 : 특수기호나 한글과 같은 희귀 언어가 포함되어있다면? UCS-4(고정 4바이트 인코딩)을 사용한다.)

오늘은 이렇게 문자를 표현하는 방식의 간단한 변천사(생략된 방법들이 분명 존재한다)를 공부해보았다. 복잡하게만 보이던 문자의 인코딩 방식들이 사실상 차지하는 메모리를 줄이기 위한 개선방식이었다는 것을 생각하니 조금 더 이해하기 수월했다.

왜 인코딩/디코딩이 필요한가?

전세계 키보드는 공통어로 영어를 사용한다. 

그럼 한글을 사용하려면 어떻게 해야 할까?

영어 한자 한자 글자에 1:1 대응되는 한글이 필요하다. 

운영체제 윈도우/리눅스 는 다른 문자체계를 가지고 있을 것이다. 처음부터 다른 사람이 만들었으니 자기 맘대로 문자체계를 만들었을 것이다. 

그럼 윈도우와 리눅스가 통신을 하면 오류가 나올것이다. 그래서 각각의 os에 대응하는 1:1 문자표가 필요할것이다. 

이렇게 우선 개념을 가져야 한다. 

그래서 이런 저런 문자set이 나온거니까, 지금 문자셋이 무엇인지 알아야 하고, 변할될 문자셋은 어떤건지 알아야 하지 않을까

​우선 이해를 돕기 위해서 문자셋의 역사를 알아봐야 한다. 그래야 쉽게 이해한다.  

컴퓨터가 미국에서 시작하여 문자를 영어로 표현해야 했다. 

처음에는 128문자로 특수문자를 추가하여 256문자로 확장되었다. 

앞의 128자(32제어코드+ 96영문자)를 아스키코드라고 말하고

뒤의 256자를(128문자+128특수문자)를 확장 아스키코드라고 말한다.

그리고 영어권 이외의 국가로 컴퓨터가 보급되면서 각 나라는 

각 나라의 문자를 사용하고 싶은 욕구를 충족하기 위하여

각 나라마다 추가적인 문자 코드를 갖게 되었다. 

우리나라도 완성형/조합형 1990년대 문자셋이 만들어 졌다. 

완성형/조합형이란

우리나라는 초성,중성,종성으로 한 문자가 구성된다. 

이때 초성,중성,종성을 모두 각각으로 인식하여 하나 하나 인식하여 조립하는 형태를 조합형이라고 한다.

완성형이란 초성,중성,종성 3가지를 하나라 인식하여 문자표를 만든것이다. 

따라서 문자표에 없는 문자는 출력할수 없다. 

각 나라별로 문자셋을 만든것을 전세계가 공통적으로 사용하기 위하여

유니코드로 발전되었다. 

2벌식 3벌식,4벌식 이란

2벌식 우리가 사용하는 자판(키보드) 그대로 이다. 

자음과 모음으로 구성되어있다. 

3벌식 초성,중성,종성으로 자판이 나뉘어져 있다. 

4벌식 - 2벌식의 확장형

자음-> 초성 자음, 종성 자음으로 나뉘고

모음-> 받침 있는 모음, 없는 모음으로 나누었다. 

각각의 장단점이 있지만,

우리는 현재 2벌식 자판을 사용하고 있다. 

http://www.unicode.org/charts/

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

http://ssaemo.tistory.com/28

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

모니터에 '가'를 입력하고 저장하면....저장방식이utf8이면 하드디스크에는  ea bo 80으로 저장한다

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo
 

우선 한글에 대한 기본 저장방식(인코딩방식)이 무엇인가가 결정되어야 한다. 

utf8방식은 ec95 8861 6263 64eb 8595 3f0a 로 저장된다. 

euckr방식은 bec8 6162 6364 b3e7 3f0a로 저장된다. 

퍼센트 인코딩이란 위의 16진수 앞에 %를 붙이면 된다. %ec %95%88%61 .....처럼

이렇게 저장된 것을 코드표에서 찾는 방법은 역으로 접근하면 된다. 

utf8방식으로 저장했다면...당연히 유니코드표에서 찾아야 할것이다. 

유니코드 3바이트로  한글을 표현하는데 이를  2바이트로 바꾸어야 한다.

한글 '안'은 3바이트로 16진수로 ec9588, 10진수로는 1110 1100 10010101 10001000이다. 

유니코드는 3바이트로  한글을 표현한다.              1110 **** 10** **** 10** ****   ....

2진수에서 이를 제거하면                                      1100    010101   001000

16진수로 표현하기 위해 4자리 단위로 끊으면                1100   0101  0100  1000 이 된다. 

즉 4비트 * 4묶음 = 16비트= 2바이트로 바뀐것이다. 

2진수를 10진수로 바꾸면                                        12      5       4     8 이 된다. 

10진수를16진수로바꾸면10-A,11-B,12-C,13-D,14-E,15-F / C      5      4     8

3바이트를 2바이트로 16진수로 바꾸면 C548 이 된다. 0xC548

유니코드표에서 찾으면 U+C548에 '안'이 존재한다. 




혹은 

자바스크립트는

Css에서는 

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo
 

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo

Utf-8 특수문자 코드표 - utf-8 teugsumunja kodeupyo