홈으로
| 무료회원가입 | 아이디/비번찾기
추천음악방송
파이썬에서 유니코드 스트림 다루기
6년 전
파이썬에서 유니코드를 다룰 때는 일반적으로 str.decode()와 unicode.encode() 메서드를 사용하여 unicode 타입과 str 타입을 상호 변환한다.

아래 예시에서는 'utf-16'으로 작성된 파일을 열어, 수직 탭(vertical tab) 코드포인트를 지운 다음, 'utf-8'로 저장한다. (깨진 XML을 다룰 때 이 방식이 매우 중요하다.)

# 파일 내용을 읽는다
with open("input.txt", "rb") as input:  
    data = input.read()

# 바이너리 데이터를 utf-16으로 디코딩한다
data = data.decode("utf-16")

# 수직 탭을 삭제한다
data = data.replace(u"\u000B", u"")

# 유니코드 데이터를 utf-8로 인코딩한다
data = data.encode("utf-8")

# 데이터를 utf-8로 저장한다
with open("output.txt", "wb") as output:  
    output.write(data)
엄청나게 큰 파일을 다룰 때가 아니라면 이 정도로도 충분하다. 하지만 큰 파일을 다룰 땐 모든 데이터가 메모리에 올라간다는 사실이 문제가 된다.

스트리밍 인코더/디코더 사용하기
파이썬 기본 라이브러리에는 codecs 모듈이 포함되어 있다. 이 모듈을 사용하면 파일을 조금씩 읽을 수 있고, 메모리에도 약간의 유니코드 데이터만 올라가게 된다.

codecs.open() 헬퍼 메서드를 사용하여 위의 예시를 최소한만 고쳐보자.

import codecs

# 입력 스트림과 출력 스트림을 연다
input = codecs.open("input.txt", "rb", encoding="utf-16")  
output = codecs.open("output.txt", "wb", encoding="utf-8")

# 유니코드 데이터 조각들을 스트리밍한다
with input, output:  
    while True:
        # 데이터 조각을 읽고
        chunk = input.read(4096)
        if not chunk:
            break
        # 수직 탭을 삭제한다
        chunk = chunk.replace(u"\u000B", u"")
        # 데이터 조각을 쓴다
        output.write(chunk)
파일은 끔찍해! 이터레이터 사용하기
파일은 다루기가 좀 지루하다. 복잡한 처리 과정에는 유니코드 데이터의 이터레이터를 다루는 편이 깔끔할 것이다.

아래는 iterdecode()를 사용하여, 파일을 유니코드 데이터 조각의 이터레이터로 읽는 효과적인 방법이다.

from functools import partial  
from codecs import iterdecode

# 특정 path의 파일을 유니코드 조각의 이터레이터로 리턴한다
def iter_unicode_chunks(path, encoding):  
    # 읽을 파일을 연다
    with open(path, "rb") as input:
        # 바이너리 파일을 바이너리 조각으로 변환한다
        binary_chunks = iter(partial(input.read, 1), "")
        # 바이너리 조각을 유니코드 조각으로 변환한다
        for unicode_chunk in iterdecode(binary_chunks, encoding):
            yield unicode_chunk
이제 iterencode() 메서드를 사용하여, 유니코드 조각의 이터레이터를 파일에 써보자.

from codecs import iterencode

# 유니코드 조각의 이터레이터를 특정 path의 파일에 쓴다
def write_unicode_chunks(path, unicode_chunks, encoding):  
    # 쓸 파일을 연다
    with open(path, "wb") as output:
        # 유니코드 조각을 바이너리로 변환한다
        for binary_chunk in iterencode(unicode_chunks, encoding):
            output.write(binary_chunk)
이 두 함수와 함께 유니코드 데이터의 스트림에서 수직 탭을 없애는 일이 마법 같이 끝난다(just becomes a case of plumbing everything together).

# 파일을 유니코드 조각 형태로 읽는다
unicode_chunks = iter_unicode_chunks("input.txt", encoding="utf-16")

# 유니코드 조각을 수정한다
unicode_chunks = (  
    chunk.replace(u"\u000B", u"")
    for chunk
    in unicode_chunks
)

# 유니코드 조각을 파일에 저장한다
write_unicode_chunks("output.txt", unicode_chunks, encoding="utf-8")  
거창하게 codecs 모듈을 사용해야 할까?
얼핏 그냥, str.decode()와 unicode.encode() 메서드를 사용하여 큰 file 객체를 바이너리 조각으로 읽고, 인코딩하고 디코딩하는 편이 간단하다고 생각할 수도 있겠다.

# 나쁜 예시. 이렇게 하지 마시오!

# 입력 스트림과 출력 스트림을 연다
with open("input.txt", "rb") as input, open("output.txt", "wb") as output:  
    # 바이너리 데이터 조각들을 순회한다
    while True:
        # 데이터 조각을 읽는다
        chunk = input.read(4096)
        if not chunk:
            break
        # 위험: 바이너리 데이터를 utf-16으로 디코딩한다
        chunk = chunk.decode("utf-16")
        # 수직 탭을 삭제한다
        chunk = chunk.replace(u"\u000B", u"")
        # 유니코드 데이터를 utf-8로 인코딩한다
        chunk = chunk.encode("utf-8")
        # 데이터 조각을 쓴다
        output.write(chunk)
불행히도 몇몇 유니코드 코드포인트는 바이너리 데이터의 한 바이트 이상으로 인코딩된다. 따라서 단순히 파일에서 바이트 조각들을 읽어서 decode() 메서드를 적용하면 예기치 않게 UnicodeDecodeError가 발생할 수도 있다. 이는 바이트 한 조각이 여러 바이트의 코드포인트로 분리되었기 때문이다.

codecs 모듈의 도구들을 사용하면 이러한 예기치 않은 충돌을 예방할 수 있다.

파이썬 3에서는?
파이썬 3에서는 훨씬 단순하게 유니코드 파일을 다룰 수 있다. 빌트인 메서드인 open()은 유니코드 데이터를 수정하거나 인코딩을 변경하는 데 필요한 기능을 포함하고 있다.

# 입력 스트림과 출력 스트림을 연다
input = open("input.txt", "rt", encoding="utf-16")  
output = open("output.txt", "wt", encoding="utf-8")

# 유니코드 데이터 조각들을 스트리밍한다
with input, output:  
    while True:
        # 데이터 조각을 읽고
        chunk = input.read(4096)
        if not chunk:
            break
        # 수직 탭을 삭제한다
        chunk = chunk.replace("\u000B", "")
        # 데이터 조각을 쓴다
        output.write(chunk)
파이썬 3의 시대다! 즐겁게 코딩하길!
추천추천 : 284 추천 목록
번호 제목
3,046
 Vimeo (비메오) API 를 사용하여 플레이어 컨트롤하기
3,045
 iframe 사용시 하단에 발생하는 공백 제거방법
3,044
 아이프레임(iframe) 전체화면 가능하게 하기
3,043
 부트스트랩(bootstrapk)에서 사용하는 class명 정리
3,042
 부트스트랩 CSS
3,041
 크롬에서 마진 조절
3,040
 PHP 현재 페이지의 도메인명이나 url등의 정보 알아오기
3,039
 PHP preg match all()
3,038
 PHP 로 웹페이지 긁어오기 모든 방법 총정리!
3,037
 [PHP] 원격지 파일 주소 노출 안하고 curl로 다운로드 받기
3,036
 PHP 함수 정리
3,035
 아이프레임(iframe) 비율 유지하면서 크기 조절하는 방법
3,034
 PHP 배열에서 무작위로 하나 뽑아주는 array rand() 함수
3,033
 PHP 정규식 정리
3,032
 PHP 정규식을 활용한 태그 및 특정 문자열 제거 및 추출 방법
3,031
 php 크롤링 또는 파싱 함수, 정규식 모음
3,030
 제이쿼리 기본 명령어
3,029
 웹페이지 가로 모드세로 모드 인식하기
3,028
 모바일 웹 화면 강제 회전(가로모드 고정)
3,027
 [HTML5]에서 frameset 대체 방법과 iframe 속성
3,026
 HTML <Audio> 사용법
3,025
 윈도우10 시스템파일 손상 (초간단 오류 복구방법!!)
3,024
 PHP 파일 존재 여부 파악하기(로컬 파일 존재 및 원격지 파일 존재)
3,023
 [CSS] 박스 세로 가운데 중앙 정렬 6가지
3,022
 CSS Layout 수평 & 수직 정렬
목록
뮤직트로트 부산광역시 부산진구 가야동 ㅣ 개인정보취급방침
Copyright (C) musictrot All rights reserved.