파이썬 - 내가 이해한 유니코드 Python

Ascii code (American Standard Code for Information Interchange, 미국 정보 교환 표준 부호)

7비트 글자 인코딩으로, 000(0x00)부터 127(0x7F)까지 총 128개의 부호가 사용된다. 1바이트를 구성하는 8비트 중에서 7비트만 쓰도록 제정된 이유는, 나머지 1비트를 통신 에러 검출을 위해 사용하기 때문이었다.


Unicode

ascii 만으로는 전 세계의 모든 문자를 한번에 다룰수 없었기 때문에 등장한 방식으로 멀티바이트를 사용한다. 한글완성형(euc-kr) 인코딩은2바이트를 사용하지만 유니코드는 아니다. 

UCS, UTF-8, UTF-16 등은 인코딩 방식의 종류이며 유니코드를 암호화하는 알고리즘을 일컫는다. 인코딩에 따라 문자하나를 고정된 멀티바이트로 표현하거나 영어는 1바이트로 처리하고 나머지는 멀티바이트로 처리할수도 있고 유동적인 바이트를 사용해 표현할수도 있다. 또한 문자하나의 바이트순서에 따라 리틀엔디안(utf-16-le), 빅엔디안(utf-16-be)으로 구분되기도하며 utf-16 인코딩과는 다른것이다.

중요한 점은 UTF-8 문자열이 유니코드를 암호화하는 한가지 방식일뿐 유니코드 자체는 아니라는 점은 헷갈리기 쉬우니 제대로 알아 두어야 한다.


encoding (인코딩) : 유니코드를 어떤방식으로 암호화할지를 말한다. UTF-8, UTF-16, UTF-16-LE등등 인코딩 방식에 따라 다르게 저장된다.


decoding (디코딩) : UTF-8, UTF-16, UTF-16-LE 등과 같이 암호화된 문자열을 유니코드로 해제(복호화)하는 것을 뜻한다.


유니코드를 바이트로 출력

>>> [hex(ord(x)) for x in u"한글"]

['0xd55c', '0xae00']


인코딩된 유니코드를 바이트로 출력

>>> [hex(ord(x)) for x in u"한글".encode('utf-8')]

['0xed', '0x95', '0x9c', '0xea', '0xb8', '0x80']


>>> [hex(ord(x)) for x in u"한글".encode('utf-16')]

['0xff', '0xfe', '0x5c', '0xd5', '0x0', '0xae']


>>> [hex(ord(x)) for x in u"한글".encode('utf-16-le')]

['0x5c', '0xd5', '0x0', '0xae']


>>> [hex(ord(x)) for x in u"한글".encode('utf-16-be')]

['0xd5', '0x5c', '0xae', '0x0']


>>> [hex(ord(x)) for x in u"한글".encode('euc-kr')]

['0xc7', '0xd1', '0xb1', '0xdb']



Unicode With Python - 유니코드와 파이썬


* 유니코드로 변환하기

우리가 보통 사용하는 문자열은 str타입이다. 간단하게 문자열 앞에 u를 붙히거나 unicode 함수를 통해서 유니코드로 변화할수 있다. 즉 unicode 함수는 문자열이 유니코드로 decoding됨을 의미한다. 반대로 얘기하면 str은 인코딩이 되어있는 뜻이 되며 기본적으로는 ascii로 인코딩 되어있는 것이다.


>>> type("text") # string

<type 'str'>


>>> type(u"text") # convert string to unicode

<type 'unicode'>


>>> type(unicode("text")) # convert string to unicode

<type 'unicode'>



* 유니코드로 코딩하기

temp.py 파일을 하나 만들고  아래와 같이 저장한 후 실행해보자.


var =  "한글"


헉!! 그저 변수에 한글을 입력했을 뿐인데 아래와 같이 에러가 발생하고 만다.. 

왜일까? Python의 기본 인코딩은 ascii로 되어 있기 때문에 ascii코드 이외의 문자로 코딩을 하게 되면 파이썬 해석기가 코드를 해석하지 못하고 에러를 토해내게 된다.


SyntaxError: Non-ASCII character '\xed' in file temp.py on line 1, but no encoding declared; seehttp://www.python.org/peps/pep-0263.html for details



한글등과 같이 유니코드를 프로그래밍에서 다루기 위해서 아래와 같은 주석문을 파일최상단에 추가해주자. 자주 사용되니 꼭 외워두자.


#_*_ coding:utf-8 _*_

var =  "한글"



*  시스템 기본 인코딩


앞서 말했듯이 Python의 시스템 기본인코딩은 ascii이다. 백문이 불여일견 확인해보자!


>>> import sys

>>> print sys.getdefaultencoding()

ascii


시스템 인코딩이 ascii이면 어떠한 문제가 발생하는지 한가지 테스트를 해보자.


#_*_ coding:utf-8 _*_

print unicode("한글")


문자열을 유니코드로 바꾸었더니 아래와 같은 에러를 출력하고 만다.

unicode(str) 함수는 인코딩된 문자열을 입력으로 받아서 디코딩을 거쳐 유니코드로 변환하는 작업을 한다. 시스템 인코딩이 ascii로 되어있기 떄문에 문자열이 7비트의 최대값인 127(0x7f)을 넘어가면 오류가 발생하게 된다. ( ascii로 표현된 문자열 '한글'은  ['0xed', '0x95', '0x9c', '0xea', '0xb8', '0x80'] 이다. )


Traceback (most recent call last):

  File "temp.py", line 2, in <module>

    print unicode("한글")

UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 0: ordinal not in range(128)



아래와 같이 sys.setdefaultencoding함수로 시스템 인코딩을 UTF-8로 변경후 다시 시도해보자.

!! 주의 : reload(sys)를 실행하지 않으면 setdefaultencoding 함수를 실행할수 없다. 꼭 기억하자!


#_*_ coding:utf-8 _*_

import sys

reload(sys)

sys.setdefaultencoding('utf-8')

print unicode("한글")


에상대로 별다른 오류없이 유니코드로 변환되어 잘 출력되었다.


한글



sys.setdefaultencoding('utf-8') 함수의 장점은 일반 문자열을 유니코드로 디코딩시 unicode 함수를 사용할수 있다는 점이다. 수많은 문자열 앞에 u를 붙이는 것은 힘든일이 될수도 있기 때문이다.



* 인코딩된 유니코드 파일 열기


유니코드 파일을 인/디코딩 하기위한 io, codecs 모듈 두가지가 있으며 파일을 열고 닫는 함수나 사용법은 기본 라이브러리에 포함됨 open, write, writelines, read, close등 모두 같다.

!! unicode("한글")은 u"한글"로 대체해도 똑같다. 단, sys.setdefaultencoding('utf-8')과 같이 유니코드 인코딩을 시스템 기본값으로 지정해 주어야 unicode("한글") 함수가 에러가 발생하지 않는다. 그렇지 않다면 잘못된 아스키값이라며 에러를 뿜을 것이다.


#_*_ coding:utf-8 _*_

import sys

reload(sys)

sys.setdefaultencoding('utf-8')


# io 모듈

import io

# Encoding Unicode to UTF-8

with io.open("filename.txt", "w", encoding='utf-8') as f:

    f.writelines(unicode("한글"))


# Decoding UTF-8 to Unicode

with io.open("filename.txt", "r", encoding='utf-8') as f:

    print f.read()



# codecs 모듈

import codecs


# Encoding Unicode to UTF-16

with codecs.open("filename.txt", "w", encoding='utf-16') as f:

    f.writelines(unicode("한글"))


# Decoding UTF-16 to Unicode

with codecs.open("filename.txt", "r", encoding='utf-16') as f:

    print f.read()


덧글

  • 질문 2021/01/13 10:03 # 삭제 답글

    [hex(ord(x)) for x in u"한글".encode('utf-8')]
    를 넣으면 아래 에러가 발생하는데 왜 그런지 알 수 있을까요?
    TypeError: ord() expected string of length 1, but int found
댓글 입력 영역