티스토리 뷰

728x90
반응형

유니코드와 UTF-8

초기에 문자를 표현하던 대표적인 방식은 ASCⅡ 인코딩 방식으로, 1바이트에 모든 문자를 표현했다. 게다가 1비트는 체크섬으로 제외하여 7비트, 즉 128글자로 문자를 표현했다. 그러다 보니 한글이나 한자 같은 문자는 2개 이상의 특수 문자를 합쳐서 표현하곤 했는데, 당연히 이런 방식은 비정상적이며, 경우에 따라서는 깨지거나 제대로 표현되지 않는 경우가 잦았다. 이런 문제를 해결하기 위해 2~4 바이트의 공간에 여유 있게 문자를 할당하고자 등장한 방식이 바로 유니코드다. 그러나 유니코드 자체는 1바이트로 표현이 가능한 영문자도 2바이트 이상의 공간을 사용하기 때문에 이를 그대로 사용하면 메모리 낭비가 심하고 따라서 이를 가변 길이 문자 인코딩 방식으로 효율적으로 인코딩하는 대표적인 방식이 바로 우리가 잘 아는 UTF-8이다.

파이썬이 버전 3으로 넘어오면서 가장 큰 변화 중 하나는 바로 문자열의 처리 방식이다. 파이썬 2 이전에는 한글을 비롯한 특수 문자들이 모두 별도로 인코딩되는 구조라서, 콘솔에서 원래 값을 제대로 출력하기가 쉽지 않았다. 그러나 파이썬 3에 이르러서는 문자열은 모두 유니코드 기반으로 전환됐고, 덕분에 많은 부분이 개선되어 파이썬 3부터는 영어뿐만 아니라 한글, 한자 등의 다국어를 출력하는데 아무런 불편함이 없다.

이제, 유니코드의 가변 길이 문자 인코딩 방식인 UTF-8의 내부 구조를 좀 더 상세히 살펴보자. 만약 모든 문자를 4바이트로 표현한다면 Python이라는 영문 문자열은 다음과 같이 24바이트의 메모리를 차지하게 될 것이다.

"""
p              y           t           h           o           n
0x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 00
"""

그런데 이 방식은 확실히 문제가 있다. 영문자 ASCⅡ 코드로도 충분히 표현이 가능하기 때문에 각 문자당 1바이트로 충분한데, 모든 문자가 4바이트를 차지하기 때문에 사실상 문자마다 3바이트씩 빈 공간으로 낭비되고 있다. 이런 문제를 해결하기 위한 여러 가지 가변 인코딩 방식이 등장했고 그중 가장 유명한 방식이 바로 UTF-8이다.

image

이 표의 이진 포맷은 매우 간단하면서도 직관적이다. 시작 비트를 살표보면 문자의 전체 바이트를 결정할 수 있다. 첫 바이트의 맨 앞 비트를 확인해서 0인 경우 1바이트 문자, 10인 경우 특정 문자의 중간 바이트, 110인 경우 2바이트, 1110인 경우 3바이트, 11110인 경우 4바이트, 이와 같은 방식으로 문자 바이트의 길이를 인식할 수 있다.

여기서 중요한 점은 유니코드 값에 따라 가변적으로 바이트를 결정하여 불필요한 공간 낭비를 절약할 수 있다는 점이다. 값이 127 이하라면 1바이트로 표현한다. ASCⅡ 문자는 128개이며, 이 문자들의 유니코드 값은 동일하므로 영문, 숫자를 포함한 기존 ASCⅡ 문자는 모두 그대로 1바이트에 표현이 가능하다.

앞서 Python이라는 문자열도 모두 ASCⅡ 문자 범위 내에 있으므로 UTF-8 인코딩으로 0x50 0x79 0x74 0x68 0x6f 0x6e로 표현할 수 있고 6바이트에 표현이 가능하다. 모든 문자를 4바이트로 표현할 경우 24바이트를 차지하는 것에 비해 4분의 1 수준에 불과한 메모리를 사용하므로 불필요한 메모리 낭비를 절약할 수 있다.

다음의 그림은 '한' 유니코드 값을 UTF-8 인코딩 값으로 표현해본 그림이다.

image





출처
파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [책만]


728x90
반응형
댓글
반응형
250x250
글 보관함
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Total
Today
Yesterday
링크