[PYTHON] 파이썬에서 BOM 문자로 유니 코드 파일 데이터 읽기
PYTHON파이썬에서 BOM 문자로 유니 코드 파일 데이터 읽기
파이썬을 사용하고 유니 코드 BOM 오류로 실행되는 일련의 소스 코드 파일을 읽습니다. 내 코드는 다음과 같습니다.
bytes = min(32, os.path.getsize(filename))
raw = open(filename, 'rb').read(bytes)
result = chardet.detect(raw)
encoding = result['encoding']
infile = open(filename, mode, encoding=encoding)
data = infile.read()
infile.close()
print(data)
보시다시피, 나는 chardet을 사용하여 인코딩을 감지하고 메모리에있는 파일을 읽고 그것을 인쇄하려고합니다. print 문은 오류가있는 BOM이 포함 된 유니 코드 파일에서 실패합니다.
기본 문자 집합을 사용하여 BOM을 디코딩하려고하면 오류가 발생합니다. 어떻게 이것을 막기 위해 문자열에서 BOM을 제거합니까?
해결법
-
==============================
1.BOM이 존재하는지 여부를 확인할 이유가 없습니다. UTF-8-SIG는 BOM이 없으면 utf-8과 똑같이 작동합니다.
BOM이 존재하는지 여부를 확인할 이유가 없습니다. UTF-8-SIG는 BOM이 없으면 utf-8과 똑같이 작동합니다.
# Standard UTF-8 without BOM >>> b'hello'.decode('utf-8') 'hello' >>> b'hello'.decode('utf-8-sig') 'hello' # BOM encoded UTF-8 >>> b'\xef\xbb\xbfhello'.decode('utf-8') '\ufeffhello' >>> b'\xef\xbb\xbfhello'.decode('utf-8-sig') 'hello'
위의 예에서 utf-8-sig는 BOM의 존재 여부에 관계없이 주어진 문자열을 올바르게 디코딩하는 것을 볼 수 있습니다. BOM 문자가 읽고있는 파일에 존재할 가능성이 적다 고 생각되면 utf-8-sig를 사용하고 걱정하지 마십시오.
-
==============================
2.utf-8-sig 인코딩을 명시 적으로 사용하지 않으면 UTF-16을 디코딩 할 때 BOM 문자가 자동으로 제거되지만 UTF-8은 제거되지 않아야합니다. 다음과 같이 시도해 볼 수 있습니다.
utf-8-sig 인코딩을 명시 적으로 사용하지 않으면 UTF-16을 디코딩 할 때 BOM 문자가 자동으로 제거되지만 UTF-8은 제거되지 않아야합니다. 다음과 같이 시도해 볼 수 있습니다.
import io import chardet import codecs bytes = min(32, os.path.getsize(filename)) raw = open(filename, 'rb').read(bytes) if raw.startswith(codecs.BOM_UTF8): encoding = 'utf-8-sig' else: result = chardet.detect(raw) encoding = result['encoding'] infile = io.open(filename, mode, encoding=encoding) data = infile.read() infile.close() print(data)
-
==============================
3.나는 Chewie의 답을 기반으로 멋진 BOM 기반 탐지기를 구성했습니다. 데이터가 알려진 로컬 인코딩 또는 BOM이있는 유니 코드 (텍스트 편집기에서 일반적으로 생성하는 것) 중 하나 일 수있는 일반적인 경우에는 충분합니다. 더 중요한 것은, chardet과 달리 임의의 추측을하지 않으므로 예측 가능한 결과를 얻을 수 있습니다.
나는 Chewie의 답을 기반으로 멋진 BOM 기반 탐지기를 구성했습니다. 데이터가 알려진 로컬 인코딩 또는 BOM이있는 유니 코드 (텍스트 편집기에서 일반적으로 생성하는 것) 중 하나 일 수있는 일반적인 경우에는 충분합니다. 더 중요한 것은, chardet과 달리 임의의 추측을하지 않으므로 예측 가능한 결과를 얻을 수 있습니다.
def detect_by_bom(path,default): with open(path, 'rb') as f: raw = f.read(4) #will read less if the file is smaller for enc,boms in \ ('utf-8-sig',(codecs.BOM_UTF8,)),\ ('utf-16',(codecs.BOM_UTF16_LE,codecs.BOM_UTF16_BE)),\ ('utf-32',(codecs.BOM_UTF32_LE,codecs.BOM_UTF32_BE)): if any(raw.startswith(bom) for bom in boms): return enc return default
-
==============================
4.2014 년 10 월 7 일 2.3.0 버전 출시 이후 자동으로 BOM_UTF8을 감지합니다.
2014 년 10 월 7 일 2.3.0 버전 출시 이후 자동으로 BOM_UTF8을 감지합니다.
#!/usr/bin/env python import chardet # $ pip install chardet # detect file encoding with open(filename, 'rb') as file: raw = file.read(32) # at most 32 bytes are returned encoding = chardet.detect(raw)['encoding'] with open(filename, encoding=encoding) as file: text = file.read() print(text)
참고 : Chardet은 텍스트에 BOM을 남기는 'UTF-XXLE', 'UTF-XXBE'인코딩을 반환 할 수 있습니다. 'LE', 'BE'는이를 피하기 위해 제거되어야합니다. 예를 들어, @ ivan_pozdeev의 대답과 같이이 시점에서 BOM을 쉽게 감지 할 수 있습니다.
Windows 콘솔에 유니 코드 텍스트를 인쇄하는 동안 UnicodeEncodeError를 피하려면 Python, 유니 코드 및 Windows 콘솔을 참조하십시오.
-
==============================
5.다른 답변은 너무 복잡합니다. 바이너리 파일 I / O의 하위 레벨 관용구에 빠질 필요가없는 더 간단한 방법이 있습니다. Python 표준 라이브러리의 일부가 아닌 휴리스틱 (chardet) 문자 세트에 의존하지 않으며 UTF-16 계열에서 아날로그가없는 것으로 보이는 대체 인코딩 서명 (utf-8-sig 대 일반적인 utf-8)이 필요합니다.
다른 답변은 너무 복잡합니다. 바이너리 파일 I / O의 하위 레벨 관용구에 빠질 필요가없는 더 간단한 방법이 있습니다. Python 표준 라이브러리의 일부가 아닌 휴리스틱 (chardet) 문자 세트에 의존하지 않으며 UTF-16 계열에서 아날로그가없는 것으로 보이는 대체 인코딩 서명 (utf-8-sig 대 일반적인 utf-8)이 필요합니다.
내가 찾은 가장 간단한 방법은 유니 코드의 BOM 문자를 처리하고 코덱을 처리하는 것입니다. 유니 코드 바이트 순서 표시가 하나뿐이므로 데이터가 유니 코드 문자로 변환되면 거기에 있는지 여부를 확인하거나 추가 / 제거하는 것이 쉽습니다. 가능한 BOM이있는 파일을 읽으려면 :
BOM = '\ufeff' with open(filepath, mode='r', encoding='utf-8') as f: text = f.read() if text.startswith(BOM): text = text[1:]
이것은 재미있는 모든 UTF 코덱 (예 : utf-8, utf-16le, utf-16be, ...)에서 작동하며 추가 모듈을 필요로하지 않으며 바이너리 파일 처리 또는 특정 코덱 상수로 떨어 뜨릴 필요가 없습니다.
BOM을 작성하려면 다음을 수행하십시오.
text_with_BOM = text if text.startswith(BOM) else BOM + text with open(filepath, mode='w', encoding='utf-16be') as f: f.write(text_with_BOM)
이것은 모든 인코딩에서 작동합니다. UTF-16 빅 엔디안은 그 예입니다.
이건 차 르벳을 기각하는 것이 아닙니다. 파일 인코딩에 사용 된 정보가없는 경우 도움이 될 수 있습니다. BOM을 추가 / 제거 할 필요가 없습니다.
-
==============================
6.@ ivan_pozdeev의 문자열 / 예외 (파일이 아닌)에 대한 대답의 변형입니다. 파이썬 예외 (http://bugs.python.org/issue2517 참조)에서 채워진 유니 코드 HTML 컨텐트를 다루고 있습니다.
@ ivan_pozdeev의 문자열 / 예외 (파일이 아닌)에 대한 대답의 변형입니다. 파이썬 예외 (http://bugs.python.org/issue2517 참조)에서 채워진 유니 코드 HTML 컨텐트를 다루고 있습니다.
def detect_encoding(bytes_str): for enc, boms in \ ('utf-8-sig',(codecs.BOM_UTF8,)),\ ('utf-16',(codecs.BOM_UTF16_LE,codecs.BOM_UTF16_BE)),\ ('utf-32',(codecs.BOM_UTF32_LE,codecs.BOM_UTF32_BE)): if (any(bytes_str.startswith(bom) for bom in boms): return enc return 'utf-8' # default def safe_exc_to_str(exc): try: return str(exc) except UnicodeEncodeError: return unicode(exc).encode(detect_encoding(exc.content))
또는,이 훨씬 간단한 코드는 많은 비싸지 않고 비 ASCII 문자를 삭제할 수 있습니다.
def just_ascii(str): return unicode(str).encode('ascii', 'ignore')
from https://stackoverflow.com/questions/13590749/reading-unicode-file-data-with-bom-chars-in-python by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 양식 전송 오류, 플라스크 (0) | 2018.10.08 |
---|---|
[PYTHON] python selenium 버튼을 클릭하십시오. (0) | 2018.10.08 |
[PYTHON] 간격 사이의 datetimes 목록 생성 (0) | 2018.10.08 |
[PYTHON] URL에서 Pandas read_csv (0) | 2018.10.08 |
[PYTHON] 파이썬의 인터프리터 출력을 캡처하고 텍스트 위젯에 표시하는 방법? (0) | 2018.10.08 |