표준 라이브러리에는 str이나 bytes 인수를 모두 받을 시, 인수의 자료형에 따라 다르게 작용하는 함수들이 있고, re 와 os 모듈이 대표적이다.
bytes로 정규 표현식을 만들 경우 \d와 \w같은 패턴은 아스키 문자만 매칭되고, str로 이 패턴을 만들 시 아스키 문자 외외에 유니코드 숫자나 문자도 매칭된다.
"""
정규 표현식을 str과 bytes에 사용할 수 있지만,
bytes에 정규 표현식을 사용하면 아스키 범위를 벗어나는 문자들은 숫자나 단어로 처리하지 않는다.
"""
import re
re_numbers_str = re.compile(r'\d+')
re_words_str = re.comile(r'\w+')
renumbers_bytes = re.compile(rb'\d+')
rewords_bytes = re.compile(rb'\w+')
text_str = ("Ramanujan saw \u0be7\u0be7\u0bed\u0be8\u0bef
" "as 1729 = 1^3 + 12^3 = 9^3 + 10^3.")
text_bytes = text_str.encode('utf_8')
print('Text', repr(text_str), sep='\n ')
print('Numbers')
print(' str :'. re_numbers_str.findall(text_str))
print(' bytes :', re_nqumbers_bytes.findall(text_bytes))
print('Words')
print(' str :', re_word_str.findall(text_str))
print(' bytes :', re_words_bytes.findall(text_bytes))
GNU/리눅스 커널은 유니코드를 모르기에 실제 os의 파일명은 어떠한 인코딩 체계에서도 올바르지 않은 바이트 시퀀스로 구성되어 있기에 str로 디코딩 할 수 없고, 다양한 운영 체계를 클라이언트로 가지는 파일 서버는 이런 문제가 발생하기 쉽다.
해결은 파일명이나 경로명을 받는 모든 os 모듈 함수는 str이나 bytes형의 인수를 받고 str 인수로 호출하면 인수는 sys.getfilesystemencoding() 함수에 의해 지정된 코덱을 이ㅛㅇ해서 자동으로 변환되고, 운영 체계의 응답은 동일 코덱을 이용해서 디코딩 되므로 유니코드 샌드위치 모델에 따라서 원하는대로 가능
#str과 bytes 인수로 호출한 listdir()메서드와 결과
os.listdir('.')
os.listdir(b'.')
파일명이 str형이면 sys.getfilesystemencoding()이 변환한 코덱명을 이용해서 파일명을 bytes형으로 인코딩한다. 그러나,파일명이 bytes형이면 변환하지 않고 그대로 반환한다.
fsdecode(파일명)
파일명이 bytes 형이면 sys.getfilesystemencoding()이 반환한 코덱명을 이용해서 파일명을 str형으로 디코딩하고, 파일명이 str형이면 변환하지 않고 그대로 반환한다.
surrogateescape를 이용해서 깨진 문자 처리하기
예상치 못한 bytes나 모르는 인코딩을 처리하기 위한 바이트 제안서의 설명을 바탕으로 python에선 surrogateescape 코덱 에러 처리기 사용
"""
디코딩할 수 없는 바이트를 유니코드 표준에서 하위 써로게이트 영역이라고 코드 포인트로 치환한다.
애플리케이션 내부 용도로 사용할 수 있도록 한다.
"""
os.listdir('.')
os.listdir(b'.')
pi_name_bytes = os.listdir(b'.')
pi_name_str = pi_name_bytes.decode('ascii',surrogateescape')
pi_name_str