안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

기타 IT 지식 (Etc)

[문자열 인코딩] ASCII, ANSI, UTF-8, UTF-16 등

피그브라더 2020. 6. 16. 23:55

이번 포스팅에서는 문자열을 바이트열로 인코딩하는 방식에 대해 알아볼 것이다. 바이트열을 문자열로 인코딩하는 방식(ex. Base 64)이 아니므로 방향성에 주의하자. 문자열 인코딩 방식에는 여러 종류가 존재하지만, 몇 가지 대표적인 인코딩 방식만을 소개한다.

 

1. ASCII (American Standard Code for Information Interchange)

흔히들 아스키 코드라고 부르는 것으로, 최초의 문자열 인코딩 방식이다. 7bit로 하나의 문자를 표현하기 때문에, 총 128개의 문자를 표현할 수 있다. 이름에서 나타나 있듯이 영어를 위한 인코딩 방식이기 때문에 일본어, 중국어, 한국어와 같이 다른 언어의 문자들은 표현할 수 없다. 이러한 단점을 보완하기 위해 등장한 문자열 인코딩 방식이 바로 ANSI이다.

 

ASCII 코드 표 (출처 :  jehyunlee.github.io/2020/02/05/Python-General-1-AsciiIter)

 

2. ANSI (American National Standard Institute)

다른 언어의 문자들을 표현하지 못하는 ASCII의 단점을 보완하기 위해 등장한 문자열 인코딩 방식이다. 8bit로 하나의 문자를 표현하기 때문에, 총 256개의 문자를 표현할 수 있다. 0x00부터 0x7F까지는 ASCII와 동일하고, 나머지 128개는 다른 언어의 문자들을 표현하는 데 사용한다. 그러나 128개만으로 다른 언어의 문자들을 전부 표현할 수 없기 때문에, 언어별로 코드 페이지(CodePage)를 만들어서 각각 다른 코드 표를 사용하도록 하였다. 즉, 하나의 코드 페이지는 특정 언어를 위한 코드 표에 해당한다. 예를 들어, 한국어에 해당하는 코드 페이지는 남은 128개의 문자들로 한국어 문자들을 표현한다. 따라서 영어만 사용할 경우에는 문제가 없겠지만, 영어가 아닌 다른 언어들을 사용하는 환경에서는 호환성이 상당히 떨어진다는 문제점이 존재한다.

 

3. EUC-KR (Extended Unix Code-Korea)

한글 지원을 위해 유닉스 계열에서 등장한 완성형 인코딩 방식으로, 2byte(= 16bit)로 하나의 문자를 표현한다. ANSI를 한국에서 확장한 것이기 때문에 다른 나라에서는 호환되지 않을 가능성이 높다. 참고로 '완성형'이란 완성된 각 문자에 코드를 부여하는 방식을 말하며, '조합형'이란 문자를 이루는 각 요소(한글로 예를 들면 초성, 중성, 그리고 종성)에 코드를 부여하는 방식을 말한다.

 

0x0000부터 0x007F까지는 KS X 1003 체계(ASCII와 동일한데 역슬래시만 원화로 바뀜)와 동일하고, 나머지 중 일부는 KS X 1001 체계와 동일하다. 그런데 KS X 1001 체계는 한글 단어를 2350자만 사전순으로 배열했기 때문에, 모든 한글 단어를 표현하기에는 역부족이라고 할 수 있다. 따라서 사용하지 않은 나머지 바이트열을 활용하여 더 많은 한글 단어를 표현할 수 있도록 개선 및 확장한 인코딩 방식이 바로 CP949이다.

 

4. CP949 (Code Page 949) 또는 MS949

한글 지원을 위해 마이크로소프트 윈도우 계열에서 등장한 확장 완성형 인코딩 방식으로, EUC-KR이 많은 한글 단어를 표현하지 못하는 문제를 보완하기 위해 등장하였다. 똑같이 2byte(= 16bit)로 하나의 문자를 표현하지만, EUC-KR이 사용하지 않는 나머지 바이트열을 활용하여 대부분의 한글 단어를 표현할 수 있도록 개선 및 확장하였다. 따라서 기본적으로 EUC-KR과는 호환이 된다. 그러나 EUC-KR에서 표현할 수 없던 한글 단어들의 경우 사전순으로 배열하지 않았다는 문제점이 존재한다.

 

949는 한국에 대응하는 코드 페이지 번호를 의미하는 것이며, 마이크로소프트가 만들었기 때문에 MS949라고도 부른다. 참고로, 윈도우 메모장에서 인코딩 방식을 ANSI로 선택하고 저장하면 실제로는 단순 ANSI가 아닌 CP949 방식에 의해 인코딩 된다는 것에 주의하도록 하자.

 

5. 유니코드 (Unicode)

본격적으로 UTF-8, UTF-16, UTF-32 등의 인코딩 방식을 알아보기 전에, 유니코드(Unicode)의 개념을 먼저 확실히 이해하고 넘어가야 한다. 많은 사람들이 유니코드와 UTF-8 등의 인코딩 방식을 같은 개념인 것으로 오해하는데, 이 둘은 개념적으로 분명히 다르다. 따라서 여기서 그 개념들을 명확히 하고 가자.

 

유니코드는 전 세계에서 사용하는 수많은 문자들 각각에 부여한 코드들의 집합으로, 전 세계의 기기들이 통일된 인코딩 방식을 사용할 수 있도록 하기 위해 고안되었다. 유니코드에서 각 문자에 부여되는 코드는 'U+XXXX'의 형식과 같이 표현된다. 예를 들어, '가'라는 글자에 부여된 코드는 'AC00'이며, 이를 'U+AC00'이라고 표현한다. 그리고 UTF-8, UTF-16, UTF-32 등은 그러한 유니코드 기반의 문자들을 바이트열에 인코딩하는 방식을 의미한다. 쉽게 말해서, 유니코드는 전 세계 문자들 각각에 맵핑된 코드들을 담고 있는 거대한 표이며, UTF-8 등의 인코딩 방식은 그러한 유니코드 표를 바탕으로 문자들을 바이트열에 표현하는 방식이라고 생각하면 된다. 

 

그렇다면 유니코드 표는 하나인데 어떻게 인코딩 방식이 여러 가지인 것일까? 방금 전까지 다루었던 ASCII, ANSI, EUC-KR, CP949 등의 인코딩 방식은 해당 코드 표에서 원하는 문자에 해당하는 코드를 찾아 그대로 바이트열에 쓰는 방식이었다. 하지만 UTF-8 등의 인코딩 방식은 그렇지 않다. 똑같은 문자도 인코딩 방식에 따라 바이트열에 다르게 표현될 수 있다. 이에 대해서는 이어지는 설명을 참조하자.

 

6. UTF-N (Universal Coded Character Set + Transformation Format - N-bit)

UTF-8, UTF-16, UTF-32는 유니코드 기반의 문자들을 바이트열에 표현하는 인코딩 방식을 의미한다. 특정 문자를 인코딩하는 절차는 기본적으로 다음과 같다. 먼저 유니코드 표에서 인코딩하고자 하는 문자의 코드를 찾는다. 다음으로, 그 코드를 각 인코딩 방식에서 정해둔 어떤 규칙에 따라 변형시켜서 바이트열에 표현한다. 표에서 찾은 코드를 그대로 바이트열에 표현하는 ASCII, ANSI 등의 인코딩 방식과는 달리, 표에서 찾은 코드를 변형하는 별도의 과정이 필요하다는 것을 알 수 있다. 이것이 동일한 유니코드 표를 사용함에도 불구하고 여러 인코딩 방식이 존재할 수 있는 이유이다. 그러면 이제 각 인코딩 방식의 변형 규칙을 간단히 살펴보자.

 

6-1. UTF-8

인코딩하려는 문자의 코드가 속한 범위에 따라 1byte ~ 4byte로 인코딩하는 가변 길이 인코딩 방식이다. 자주 사용되는 문자는 짧은 바이트로 표현하고 그렇지 않은 문자는 긴 바이트로 표현함으로써 저장 공간을 효율적으로 사용한다. 기본적으로 첫 128개의 문자(0x0000 ~ 0x007F 범위에 속하는 ASCII 문자)들은 특별한 변형 없이 1byte에 그대로 인코딩 되기 때문에, 영어만 사용할 경우 문자 하나 당 1byte만 사용하게 된다. 그러나 만약 중동, 유럽 지역의 언어를 사용한다면 문자 하나 당 2byte를 사용하게 되고, 동아시아권 언어를 사용한다면 3byte 이상까지도 사용하게 된다.

 

UTF-8 인코딩 규칙은 다음 표에 나타나 있다. 예를 들어, '가'의 코드는 16진수로 AC00이고 2진수로 10101100 00000000이다. 이는 000800-00FFFF 범위에 속하기 때문에, 위 표에 따르면 1110xxxx 10xxxxxx 10xxxxxx의 x 자리에 순서대로 2진수 코드를 채워 넣으면 인코딩이 완료된다. 그러면 11101010 10110000 10000000이 되고, 이를 다시 16진수로 표현하면 EA B0 80이다. 결국, '가'라는 글자는 UTF-8 방식에 따라 EA B0 80로 인코딩 된다는 것을 알 수 있다.

 

 

6-2. UTF-16

UTF-8이 8bit 기반의 인코딩 방식이라면, UTF-16은 16bit 기반의 인코딩 방식이다. 그렇다고 해서 16bit 고정 길이로 인코딩하는 것은 아니고, 이 역시 UTF-8과 마찬가지로 가변 길이 인코딩 방식이다. 자주 사용하는 문자는 2byte, 그렇지 않은 문자는 4byte로 표현한다. 한글을 사용함에 있어, 한글을 3byte로 표현하는 UTF-8과 달리 UTF-16은 한글을 2byte로 인코딩할 수 있기 때문에 저장 공간을 더욱 효율적으로 쓸 수 있다는 장점이 있다. 그러나 ANSI와 호환이 되지 않는 문제, Byte Ordering을 고려해야 하는 문제 등으로 인해 UTF-8보다는 사용의 복잡성이 높다는 단점이 있다. 다음은 UTF-16 인코딩 규칙을 나타내는 표이다.

 

 

6-3. UTF-32

모든 문자를 4byte(= 32bit)의 고정 길이로 인코딩한다. 별도의 변형 규칙은 존재하지 않고, 표에서 찾은 코드를 4byte로 늘려서 바이트열에 그대로 표현하면 끝이다. 이는 코드 변형 규칙이나 가변 길이에 대한 특별한 고려를 하고 싶지 않을 때, 일관성 있고 단순한 방식으로 문자열을 처리할 수 있다는 장점이 있다. 그러나 하나의 문자를 저장하는데 너무 많은 저장 공간이 사용되고 이것 또한 UTF-16과 마찬가지로 Byte Ordering을 고려해야 하는 문제가 있기 때문에 자주 사용되지는 않는 인코딩 방식이다.