본문 바로가기

파이썬 기초

파이썬 에러 해결 방법 UnicodeDecodeError / UnicodeEncodeError

파이썬에서 파일 열기/읽기를 실행하다 보면 아래와 같이 UnicodeDecodeError: 'cp949' codec can't decode byte...이라는 에러를 접하는 경우가 있습니다.

UnicodeDecodeError

결론적으로 해결 방법은 파일 열기/읽기를 할 경우 인코딩을 UTF-8로 지정을 하게 되면 해결이 가능하다. 

[해결 방법]

with open(file_name, 'r') as file:  -> with open(file_name, 'r', encoding='UTF-8') as file:

 

마찬가지로 파일 열기/쓰기의 경우에도 아래와 같이 UnicodeEncodeError: 'cp949' codec can't encode character...라는 에러가 발생하는 경우가 있습니다.

UnicodeEncodeError

해결 방법은 동일하게 인코딩을 UTF-8로 지정하면 됩니다. 

[해결 방법]

with open(file_name, 'w') as file:  -> with open(file_name, 'w', encoding='UTF-8') as file:

 

Unicode, cp949, UTF-8의 개념 이해하기

처음으로 다시 돌아가서 파일 열기에서 에러가 발생하였던 이유는 'cp949' 코덱은 0xe2 바이트를 디코드(decode)할 수 없다는 내용이고 파일 쓰기에서 에러가 발생하였던 이유는  'cp949' 코덱은 \xf1이라는 문자를 인코드(encode)할 수 없다는 것입니다.

 

여기서 'cp949'는 한글 인코딩의 한 종류이며 EUC-KR의 확장 완성형이다.

EUC-KR는 한글 중 2350자만 지원하고 있기 때문에 여기에 포함 안 되는 문자의 경우 표기에 문제가 발생하게 된다. 이러한 문제점을 개선하고자 마이크로소프트에서 8,822자를 인코딩에 추가한 것이 'cp949'입니다.

 

CP949에서 새로이 추가된 8,822자는 다음 규칙에 따라 가나다순을 차례대로 2바이트로 할당되어 있으며 일부 한자도 포함되어있습니다. 아스키 값은 그대로 1바이트로 표현됩니다.
  • 첫 번째 바이트는 0x81~0xC6 사이를 할당받는다.
  • 두 번째 바이트는 0x41~0x5A (대문자 A~Z), 0x61~0x7A (소문자 a~z), 0x81~0xFE를 할당받는다.
  • 단, EUC-KR와의 충돌을 피하기 위해, 첫 번째 바이트가 0xA1 이상인 경우에는 두 번째 바이트가 0xA0을 초과하지 않도록 제한한다.

아래는 CP949 코드표의 일부이며 0xe2\xf1는 정의되어 있지 않기 때문에 발생하는 에러입니다.

CP949 code table

CP949 코드표 전체는 아래 엑셀 파일 참조하세요.

CP949.xlsx
0.16MB

 

따라서 유니코드 에러는 문자를 인코딩한 방식으로 디코딩을 해주게 된다면 모두 해결할 수가 있습니다.

 

추가적으로 이해를 하기 위해 유니코드와 인코딩 방식에 대해서 소개합니다.

 

유니코드(Unicode)는 전 세계의 모든 문자를 특정 숫자와 1:1로 매핑해 놓은 코드표입니다.

유니코드 값을 나타내기 위해서는 코드 포인트(code point)를 사용하는데, 보통 U+ 를 붙여 표시하고, 코드 앞에 U+라는 문자가 붙어있으면 유니코드라는 의미입니다.

모두가 잘 알고 있는 알파벳 대문자 A의 아스키(ASCII) 코드는 0x41이지만, 이를 유니코드 표에서 찾으면 U+0041이 됩니다.

그러면 한글 '한'이라는 문자를 유니코드 표에서 찾아보면 U+D55C가 됩니다.

Unicode table

 

문자 집합을 컴퓨터에 저장하기 위해서 옥텟(octet, 8비트 단위) 형태로 표현한 것을 인코딩 방식이라고 하는데 이러한 인코딩 방식에 코드 포인트를 코드화 하는 UCS-2와 UCS-4 인코딩과 변환 인코딩 형식인 UTF-8, UTF-16, UTF-32 인코딩 등이 있습니다. 이 중에서 ASCII와 호환이 가능한 UTF-8 인코딩이 가장 많이 사용되고 있습니다. 

 

UTF-8, UTF-16 같은 인코딩 방식은 이 유니코드 표의 숫자 키들을 어떻게 표현하느냐에 따라 달린 것이다. 예를 들어 UTF-8은 가변 바이트를 사용하기 때문에, 1바이트로 표현이 충분한 A 같은 경우는 0x41로 표현한다. 반면 UTF-16은 16비트 즉, 2바이트로 표현하기 때문에, 0x0041로 표현한다. UTF-32도 있는데, 4바이트로 표현하기 때문에 0x00000041이 됩니다.