회원가입아이디/비번찾기
홈으로

파이썬에서 유니코드 스트림 다루기
8년 전
파이썬에서 유니코드를 다룰 때는 일반적으로 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의 시대다! 즐겁게 코딩하길!
추천추천 : 333 추천 목록
번호 제목
2,885
input 입력 필드 앞뒤 공백 실시간 제거
2,884
Placeholder 포커스시 감추기
2,883
MySQL 중복된 데이터를 삭제
2,882
MySQL 중복 데이터 확인
2,881
sessionStorage.getItem 와 sessionStorage.setItem
2,880
제이쿼리 랜덤으로 배경색 변경
2,879
preg match에 관한 정규식
2,878
Stream an audio file with MediaPlayer 오디오 파일 스트리밍 하기
2,877
Audio Streaming PHP Code
2,876
PHP $ SERVER 환경 변수 정리
2,875
Vimeo (비메오) API 를 사용하여 플레이어 컨트롤하기
2,874
iframe 사용시 하단에 발생하는 공백 제거방법
2,873
아이프레임(iframe) 전체화면 가능하게 하기
2,872
부트스트랩(bootstrapk)에서 사용하는 class명 정리
2,871
부트스트랩 CSS
2,870
크롬에서 마진 조절
2,869
PHP 현재 페이지의 도메인명이나 url등의 정보 알아오기
2,868
PHP preg match all()
2,867
PHP 로 웹페이지 긁어오기 모든 방법 총정리!
2,866
[PHP] 원격지 파일 주소 노출 안하고 curl로 다운로드 받기
2,865
PHP 함수 정리
2,864
아이프레임(iframe) 비율 유지하면서 크기 조절하는 방법
2,863
PHP 배열에서 무작위로 하나 뽑아주는 array rand() 함수
2,862
PHP 정규식 정리
2,861
PHP 정규식을 활용한 태그 및 특정 문자열 제거 및 추출 방법
2,860
php 크롤링 또는 파싱 함수, 정규식 모음
2,859
제이쿼리 기본 명령어
2,858
웹페이지 가로 모드세로 모드 인식하기
2,857
모바일 웹 화면 강제 회전(가로모드 고정)
2,856
[HTML5]에서 frameset 대체 방법과 iframe 속성
목록
뮤직트로트 부산광역시 부산진구 가야동 ㅣ 개인정보취급방침
Copyright ⓒ musictrot All rights reserved.