본문 바로가기
Python/기초

[파이썬/Python] 인코딩(encoding)에 대한 깔끔한 정리

by 모두의 케빈 2023. 7. 9.

인코딩(encoding)은 무엇인가?


 

컴퓨터는 문자를 인식할 수 있을까. 컴퓨터는 0과 1로 이루어진 2진법의 세계에 살고 있습니다. 문자는 숫자가 아니기 때문에 컴퓨터는 인식할 수 없습니다. 그들의 언어가 아니니까요.

현실 세계에서는 암호라는 개념이 있습니다. 암호는 기준표를 활용하여 하나의 언어를 다른 암호 기호로 바꿔서 보안을 유지합니다.

인코딩(encoding)이란 암호와 유사합니다. 사전에 정의된 국제 기준이나 규칙 등을 이용하여 사람의 언어를 컴퓨터의 언어인 숫자로 바꿔주는 개념이 인코딩입니다. 그리고 컴퓨터의 언어를 사람의 언어로 바꿔주는 개념은 디코딩(decoding)이라고 합니다. 디코딩은 암호를 해석하는 과정과 유사하다고 생각하시면 됩니다.

 

 

인코딩의 종류


 

정보기관마다 고유의 암호 체계가 있듯이, 인코딩 기준이나 규칙도 여러 종류가 있습니다. 우선 순서대로 알아보겠습니다.

 

아스키코드(ASCII)

아스키코드는 가장 초창기적이고 전통적인 인코딩 방법입니다. 1byte 인코딩이며, 총 128개의 문자코드를 컴퓨터가 인식할 수 있도록 변환을 지원합니다. C언어와 같은 고급 프로그래밍언어에서 아스키코드를 볼 수 있습니다.

그러나 128개의 문자코드로는 모든 국가의 언어를 인코딩할 수 없습니다. 아스키코드는 영어와 일부 특수문자(통상 특수문자)의 변환만 지원합니다. 그래서 비영어권 국가의 언어는 인코딩할 수 없다는 단점이 있습니다.

 

EUC-KR

아스키코드는 영어와 일부 특수문자만 지원합니다. 그래서 비영어권 국가도 인코딩 변환을 위해 각자 자국의 기준에 따라 문자표를 만듭니다. EUC-KR도 이때 탄생한 문자열 셋이고, EUC-KR 같은 경우에는 영어, 한글을 포함하여 한자는 일본어를 지원합니다. 아스키코드가 1byte 인코딩이라면 EUC-KR은 2byte 인코딩입니다.

EUC 방식의 최대 단점은 나라마다 그들의 문자열 셋을 만들어서 인코딩 규칙이 통일되지 않았다는 점입니다. 한국이 나름의 기준으로 문자열 셋을 만들었겠지만, 이 기준이 태국과 인도 같은 다른 나라의 기준과는 달랐기 때문에 많은 문제가 발생했다고 합니다. (EUC-KR, EUC-JP 등... 다들 각자 언어를 만들기 바빴던 시절)

뿐만 아니라, 아스키코드가 영어 이외 문자를 지원하지 않았듯이, EUC 방식도 문자열에 정의된 언어를 제외한 다른 나라의 언어는 지원하지 않았기 때문에 아스키코드의 확장판일 뿐, 근본적인 해결책이 될 수는 없었습니다. (예를 들면, EUC-KR은 한글, 일본어, 중국어, 영어만 지원하기 때문에 태국어나 인도어는 EUC-KR 방식으로는 표현할 수 없습니다.)

 

유니코드(UniCode)

전 세계 언어를 통일된 규칙으로 표현하자는 목적으로 유니코드가 등장합니다. 유니(Uni)는 우주를 뜻하는 Universe에서 따왔으며 너(U, you) 그리고(n, and) 나(me, I)를 의미합니다.

유니코드는 전 세계 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계된 산업 표준입니다. 유니코드 협회에서 관리하고 있으며 1991년 10월에 최초 발표된 이후, 꾸준히 버전 업그레이드 되어서 현재 최신 버전은 22년 9월 14일에 발표된 15.0 버전입니다.

유니코드에서는 문자를 "U+16진수"의 코드로 변환시킵니다. 예를 들면 한글의 '가'는 16진수로 AC00(10진수의 44032)라는 코드 넘버로 정의되어 있습니다. 유니코드 체계에서 '가'는 'U+AC00'이라고 표기됩니다.

 

UTF-8

UTF-8은 유니코드를 위한 가변 길이 문자 인코딩 방식 중 하나로, 유니코드의 기준을 참고하여 문자를 인코딩합니다. 유니코드는 단순히 규칙이자 기준 체계(상위 개념)이고, UTF-8은 이를 활용하여 문자를 인코딩하는 방법 중 하나인 셈입니다.

가변 길이 문자 인코딩 방식은, 국가의 언어에 따라 byte를 다르게 할당하여 표현한다는 의미입니다. 예를 들면 아스키코드(ASCII)의 모든 문자들, 영어와 통상 특수문자는 유니코드에서 U+0000부터 U+007F까지 할당되어 있습니다. UTF-8에서 이 범위의 언어들은 1byte로 인코딩합니다.

한글은 유니코드에서 U+AC00부터 U+D7AF까지의 범위를 갖습니다. UTF-8은 이 범위의 언어들은 대부분 3byte로 인코딩합니다. 한글은 영어보다 크기가 큰 셈입니다.

 

참고 1: 1byte로 인코딩? 3byte로 인코딩?

1byte(바이트)는 8bit입니다. 1bit은 0 또는 1을 표현할 수 있습니다. 1byte로 인코딩한다는 말은 하나의 문자를 8개의 2진법 숫자로 표현한다는 뜻입니다. 예를 들면 'A'를 00000001(2) 이렇게 표현한다는 뜻입니다. 한글은 3byte, 24bit이므로 '가'는 000000000000000000000001(2) 이렇게 표현될 수 있겠네요. 물론 'A'나, '가'가 실제로 저 2진법 숫자라는 뜻은 아니고 이해를 돕기 위한 단순 예시입니다.

 

참고 2: CP949

CP949는 마이크로소프트(MS)가 제정한 규격으로 한글 Window 98에 처음으로 탑재된 인코딩 기준 체계입니다. EUC-KR을 확장한 개념이어서 한국어 웹사이트 중에는 EUC-KR과 CP949를 함께 사용하는 경우가 많았습니다.
윈도우 커널에는 유니코드가 적용되었지만 한글 윈도우의 명령 프롬프트가 사용하는 기본 인코딩은 여전히 CP949라서 C나 C++ 등의 전통 프로그래밍 언어로 한글을 출력하면 CP949 방식으로 인코딩 된다고 합니다.
국제 협약이 아닌 MS 독자 체계여서, 많은 질타를 받았다고 합니다.

 

 

 

인코딩은 왜 알아야 할까?


UnicodeDecodeError: 'utf-8' codec can't decode byte ...

 

파이썬에서 엑셀이나 csv 같은 파일을 다루다 보면 UnicodeDecoderError를 경험하셨거나 또는 높은 확률로 경험하시게 될 수밖에 없는데요.

위의 설명 글을 읽으셨다면 이제 이 에러가 왜 발생했는지 이해가 되실 겁니다. 다루고자 하는 파일이 EUC-KR 방식의 인코딩 체계를 따른다면, UTF-8의 규칙을 참고하여 디코딩하면 에러가 발생합니다. 반대의 경우도 에러가 발생하겠죠.

정확한 원인을 모른 채, 구글링 하여 방법만 찾아서 코드를 수정하셨다면 '다음에도 혹시나 이런 에러가 발생하지 않을까?' 하는 불안감에 새로운 코드를 짜는 것이 두려우실 수 있습니다. 개념을 정확히 안다면 정말 단순한 이유인데 말이죠. 

인코딩은 "해결해도 본전, 못하면 스트레스"라는 말이 있습니다. 인코딩 규칙을 알아두실 필요는 없지만, 적어도 그 개념 정도만 이해하신다면 에러가 발생하더라도 가벼운 마음으로 조치하실 수 있을 겁니다.

 

 

인코딩 실습: encode() 

 

인코딩의 개념에 대해 배웠으니, 이제 실체를 확인하기 위해 실습을 해보겠습니다. encode() 메서드를 활용하면 입력한 문자가 어떤 규칙으로 인코딩 되어있는지 확인할 수 있습니다.

 

먼저 한글에 대해 실습해 볼까요. '한글'이라는 값을 EUC-KRr, CP949, UTF-8 방식의 인코딩으로 변환했습니다. CP949는 EUC-KR의 확장판이어서 그런지 인코딩 된 규칙이 동일하네요. UTF-8은 이 둘과는 다릅니다.

kor = '한글'

print(kor.encode('euc-kr'))
print(kor.encode('cp949'))
print(kor.encode('utf-8'))

# 위 코드의 결과값
b'\xc7\xd1\xb1\xdb'
b'\xc7\xd1\xb1\xdb'
b'\xed\x95\x9c\xea\xb8\x80'

 

반면 영어는 어떤 인코딩 체계에서도 동일한 값이 나오네요.

eng = 'English'

print(eng.encode('euc-kr'))
print(eng.encode('cp949'))
print(eng.encode('utf-8'))

# 위 코드의 결과값
b'English'
b'English'
b'English'

 

 

이제 여러분은 한글 파일을 다룰 때, 글자가 깨지거나 에러가 발생하는 이유에 대해 이해하실 수 있으실 겁니다. 이 내용이 많은 도움이 되었으면 좋겠습니다.

 

댓글