Skip to Content
Dev Environment & ToolsPython 2.x 한글 인코딩 완전 정복 (UnicodeDecodeError 해결)
🛠️ Dev Environment & Tools2018년 11월 7일

Python 2.x 한글 인코딩 완전 정복 (UnicodeDecodeError 해결)

#python#unicode#encoding#python2#utf-8

Python 2.x로 작성된 레거시 코드에서 한글을 다루다 보면 어김없이 마주치는 오류가 있습니다.

plaintext
UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 0

Python 2의 기본 인코딩이 ASCII이기 때문에 발생하는 문제입니다. 원인과 해결법을 단계별로 정리합니다.

참고: Python 3에서는 기본 인코딩이 UTF-8로 바뀌어 이 문제가 대부분 해소됩니다. 가능하다면 Python 3으로 마이그레이션하는 것이 근본적인 해결책입니다.


문제의 원인: str vs unicode

Python 2에는 두 가지 문자열 타입이 공존합니다.

타입설명리터럴
str바이트 시퀀스. 기본 인코딩 ASCII"hello"
unicode유니코드 코드포인트u"안녕"
python
# Python 2에서의 함정 s = "안녕" # str 타입 → bytes (UTF-8 인코딩된 바이트) u = u"안녕" # unicode 타입 → 유니코드 코드포인트 # ASCII str과 unicode를 + 연산하면 암묵적 변환 → 오류 발생! result = s + u # UnicodeDecodeError!

해결 방법 1: 파일 인코딩 선언

소스 파일 최상단에 인코딩을 선언합니다. Python 2.x에서 한글이 포함된 파일은 반드시 필요합니다.

python
# -*- coding: utf-8 -*- name = "홍길동" # 이제 SyntaxError 없이 파싱됨

해결 방법 2: 유니코드 리터럴 사용

문자열 앞에 u를 붙여 명시적으로 unicode 타입으로 선언합니다.

python
# -*- coding: utf-8 -*- # str 타입 (바이트) name_str = "홍길동" # unicode 타입 (권장) name_uni = u"홍길동" print(type(name_str)) # <type 'str'> print(type(name_uni)) # <type 'unicode'>

해결 방법 3: encode / decode 명시적 변환

외부에서 받아온 바이트 문자열은 decode로 unicode로 변환하고, 출력할 때는 encode로 다시 바이트로 변환합니다.

python
# -*- coding: utf-8 -*- # 바이트(str)로 받은 한글 → unicode로 디코딩 raw_bytes = "안녕하세요" # UTF-8 바이트 decoded = raw_bytes.decode("utf-8") # unicode 타입으로 변환 # unicode → 바이트(str)로 인코딩 encoded = decoded.encode("utf-8") print(type(decoded)) # <type 'unicode'> print(type(encoded)) # <type 'str'>

해결 방법 4: 시스템 기본 인코딩 변경

스크립트 시작 시 Python의 기본 인코딩을 UTF-8로 강제 변경합니다. 외부 라이브러리가 내부적으로 str 연산을 하는 경우에도 효과적입니다.

python
# -*- coding: utf-8 -*- import sys reload(sys) sys.setdefaultencoding("utf-8")

이 방법은 전역 설정을 변경하므로 부작용이 있을 수 있습니다. 코드의 특정 지점에서만 인코딩 처리를 하는 방식을 우선 고려하세요.


해결 방법 5: codecs 모듈로 파일 입출력

파일을 읽고 쓸 때 인코딩을 명시적으로 지정합니다.

python
# -*- coding: utf-8 -*- import codecs # UTF-8 인코딩으로 파일 읽기 → unicode 타입으로 반환 with codecs.open("data.txt", "r", encoding="utf-8") as f: content = f.read() # unicode 타입 # unicode → UTF-8로 파일 쓰기 with codecs.open("output.txt", "w", encoding="utf-8") as f: f.write(u"한글 출력")

실전 패턴: 한글 처리 함수 래퍼

레거시 코드베이스에서 일관되게 사용할 수 있는 유틸리티 함수입니다.

python
# -*- coding: utf-8 -*- def to_unicode(s, encoding="utf-8"): """str 또는 unicode를 안전하게 unicode로 변환""" if isinstance(s, unicode): return s elif isinstance(s, str): return s.decode(encoding) else: return unicode(s) def to_str(u, encoding="utf-8"): """unicode 또는 str을 안전하게 UTF-8 str로 변환""" if isinstance(u, unicode): return u.encode(encoding) elif isinstance(u, str): return u else: return str(u) # 사용 예시 name = to_unicode("홍길동") # → unicode output = to_str(u"안녕") # → UTF-8 바이트

Python 3 마이그레이션 시 주의사항

Python 3에서는 str이 곧 unicode이고, 바이트는 bytes 타입으로 명확히 분리되어 이 혼란이 사라집니다.

python
# Python 3 에서는 name = "홍길동" # str = unicode (그냥 씀) raw = name.encode("utf-8") # bytes 타입 back = raw.decode("utf-8") # str 타입으로 복원

2to3 도구를 사용하면 Python 2 코드를 3으로 자동 변환해볼 수 있습니다.

shell
$ 2to3 -w my_script.py
Last updated on