[Fluent Python] 4장 텍스트와 바이트

4장 텍스트와 바이트

문자 문제

바이트에 대한 기본지식

bytes와 bytearray가 있는데, 전자는 파이썬3에 추가된 불변형, 후자는 파이썬 2.6에 추가된 가변형

s[0] == s[:1]이 되는 시퀀스 형은 str이 유일하다. 그 외 모든 시퀀스는 s[i]는 항목 하나를, s[i:i+1]은 s[i] 항목을 가진 동일한 자료형의 시퀀스를 반환한다.

구조체와 메모리뷰

메모리뷰는 바이트를 복사하지 않고, 뷰만 제공한다. 다음 코드는 GIF파일을 읽어서 헤더 정보를 알아낼 수 있다.

>>> import struct
>>> fmt = '<3s3sHH' # <는 리틀 엔디언, 3바이트 시퀀스 2개, 그리고 short int 2개를 의미한다.
>>> with open('image.gif', 'rb') as fp:
...     img = memoryview(fp.read())
...
>>> header = img[:10]
>>> struct.unpack(fmt, header)

이미지 파일은 mmap 모듈을 이용하여 메모리 맵 파일로 열면 훨씬 적은 바이트로 처리 가능하다. 관련 자료는 다음과 같다.

BOM(Byte Order Mark): 유용한 깨진 문자

b'\xff\xfe'가 문자열 가장 앞에 나오는데, 리틀엔디언을 표시하고, 바이트 순서가 최하위 바이트부터 시작한다는 것을 의미한다. 반대로 빅엔디언은 최상위 바이트부터 차례대로 쓰여진다. utf-16le와 utf-16be 와 같이 미리 지정하면 BOM 를 생성하지 않는다.

엑셀파일의 경우, UTF8를 탐지하기 위하여 BOM에 의존하는데, BOM이 없는 경우, 윈도우 코트페이지로 인코딩되어 있다고 가정한다. 그래서 맥용 엑셀에서는 한글이 깨지는데, csv 파일에 BOM을 넣어주면 글자가 깨지지 않는다.

텍스트 파일 다루기

인코딩을 지정하지 않으면, 시스템 기본 인코딩을 이용하기 때문에, 윈도우에서 제대로 동작하지 않을 가능성이 높다.

따라서 기본 인코딩에 의존하지 않고, 늘 인코딩을 명시하는 것이 좋다.

유니코드 정규화하기

NFC, NFD로 정규화할 수 있다. unicodedata 모듈에 normailze 함수를 이용한다. 호환성 문자로 변환하는 경우, NFKC와 NFKD가 있다.

유니코드 텍스트 정렬하기

비아스키 텍스트는 locale.strxfrm() 함수를 정렬 키로 이용하여 정렬할 수 있다. 하지만 특정 시스템이나 환경에서 제대로 동작하지 않을 수도 있다.

더 간단한 방식은 PyUCA 라이브러리가 있다. 유니코드 대조 알고리즘을 이용한 정렬방식이다.

re 모듈 대신 regex라는 모듈이 유니코드를 더욱 잘 지원한다. 그러나 여전히 해결되지 않은 문제점이 존재한다.

정규표현식에서의 str과 bytes

정규표현식에서 bytes는 아스키 범위를 벗어나는 문자는 무시한다. str 정규 표현식에서 아스키만 검색할 때는 re.ASCII 플래그가 있다.

os 모듈 함수에서 str과 bytes

다국적 사용자를 대상으로 서비스를 하는 경우, 서버에서 파일명이 문제가 될 수 있다. 기본적으로 유니코드를 지원하더라도. 예상치 않은 바이트에 대해 문제가 발생할 것을 방지하기 위해 surrogateescape 에러 처리기가 있다.