파이썬 인코딩

파이썬 인코드 디코드

파이썬 인코딩 선언

파이썬은 스크립트의 맨 처음에 위치한 주석이 coding [=:]\s*([-\w.]+)의 정규 표현식에 일치하면 그 주석은 인코딩 선언으로 인식합니다.

 

파이썬에서 인코딩 선언이 없으면 파이썬 최신 버전의 경우 기본적으로 utf-8로 인식을 합니다. 하지만 파이썬 구 버전의 경우 시스템 locale설정을 따라가므로 구 버전의 경우에는 반드시 통일화된 인코딩 선언을 해주어야 합니다.

 

utf-8의 파이썬 인코딩 선언 방법입니다. 이 선언은 주석을 포함한 어떠한 코드도 없어야 합니다. 마치 쉘 스크립트의 쉬뱅과 비슷합니다. 참고로 쉬뱅 코드 밑에 인코딩 선언을 해도 제대로 인식하는 것을 확인하였습니다.

 

#!/usr/local/bin/python3
#-*- coding:utf-8 -*-

 

정규표현식을 보니 콜론 대신에 equal 부호를 사용해도 됩니다.

 

#-*- coding=utf-8 -*-

 

만약 VIM을 사용하시는 분이라면 다음과 같이 인코딩을 선언할 수 있습니다. 이는 VIM의 설정이므로 위에서 언급한 인코딩 정규 표현식과 일치하지 않습니다.

 

# vim:fileencoding=utf-8

 

이렇게 선언을 하고 생성된 파일이 UTF8의 BOM (b'\xEF\xBB\xBF')으로 시작되면 인코딩이 UTF-8로 선언된 것으로 간주합니다.

 

파이썬 최신 버전의 경우 이렇게 인코딩 선언을 해주면 대부분 문제가 해결됩니다. 간혹 서버에 설치된 서비스(DB 등)의 캐릭터 셋이 맞지 않아 문제가 발생할 경우가 있습니다. 이럴 때 꼭 해당 캐릭터 셋을 사용해야 하는 것이 아니라면 전 세계적으로 많이 사용하는 utf-8 캐릭터 셋으로 변경해 사용할 것을 권장합니다.

 

참고로 DB의 경우에는 중간에 DB 캐릭터 셋 설정을 변경하면 이미 저장된 한글 텍스트가 모두 깨질 수 있으니 주의해야 합니다.

 

 

 

파이썬 구 버전의 인코딩 문제

아직 필자의 경우 파이썬 3.7 버전에서 한글 인코딩 문제가 발생한 경우가 없습니다. 그만큼 파이썬 버전이 올라가면서 기존의 문제점 들을 해결한 듯싶습니다. 물론 완벽하지는 않습니다.

 

만약 인코딩 선언을 했음에도 파이썬 구 버전의 경우 한글이 깨지는 경우가 발생할 때가 있습니다. 그럴 때 sys패키지를 사용하여 인코딩 방식을 강제로 변환하는 방법이 있습니다. 단, 자세한 버전은 확인 못했지만 필자가 사용하는 파이썬 3.7 버전에는 reload 함수가 imp패키지로 이동하여 reload를 하기 위해서는 from imp import reload를 해주어야 합니다. 

 

또한 sys패키지의 setdefaultencoding() 메서드가 없어져 최신 버전에서는 사용 불가능한 코드입니다. 하지만 구 버전을 사용하시는 분들을 위해 기록으로 남겨 둡니다.

 

import sys

reload(sys)
sys.setdefaultencoding('utf-8')

 

이렇게 했음에도 불구하고 여전히 글자가 깨지는 경우가 있습니다. 그럴 경우 문자열을 직접 디코딩한 후 인코딩하는 방법밖에는 없습니다. 단, 디코딩 시 인자로 주는 locale정보가 정확해야 합니다.

 

str.decode('cp949').encode('utf-8')

 

 

파이썬 2 버전의 경우 unicode()를 이용할 수도 있습니다.

 

unicode(str_cp949, 'cp949').encode('utf-8')

 

 

파이썬 디코드

decode에는 부가적으로 주로 4가지 옵션을 줄 수 있습니다.

 

1. strict : 기본값으로 UnicodeDecodeError 에러 발생

2. replace : U+FFFD의 값으로 변환

3. ignore : 유니코드에서 결과를 생략

4. backslashreplace : 이스케이스 시퀀스 (\xNN)를 삽입

 

>>> b'\x90CaptainBIN'.decode('utf-8', 'strict')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x90 in position 0: invalid start byte
>>>
>>> b'\x90CaptainBIN'.decode('utf-8', 'replace')
'�CaptainBIN'
>>> b'\x90CaptainBIN'.decode('utf-8', 'backslashreplace')
'\\x90CaptainBIN'
>>> b'\x90CaptainBIN'.decode('utf-8', 'ignore')
'CaptainBIN'

 

MORE