텍스트 인코딩을 결정하는 방법은 무엇입니까?


답변:


225

인코딩을 항상 올바르게 감지하는 것은 불가능 합니다.

(chardet FAQ에서 :)

그러나 일부 인코딩은 특정 언어에 최적화되어 있으며 언어는 임의적이지 않습니다. 일부 문자 시퀀스는 항상 팝업되지만 다른 시퀀스는 의미가 없습니다. 신문을 개봉하고 "txzqJv 2! dasd0a QqdKjvz"를 발견 한 영어에 능숙한 사람은 영어가 아님을 완전히 인식합니다 (영어로만 구성되어 있음에도 불구하고). 많은 "일반적인"텍스트를 연구함으로써 컴퓨터 알고리즘은 이러한 유창함을 시뮬레이션하고 텍스트 언어에 대한 교육 된 추측을 할 수 있습니다.

이 연구를 사용하여 인코딩을 감지 하는 chardet 라이브러리가 있습니다. chardet은 Mozilla 자동 감지 코드의 포트입니다.

UnicodeDammit 을 사용할 수도 있습니다 . 다음 방법을 시도합니다.

  • 문서 자체에서 발견 된 인코딩 (예 : XML 선언 또는 http-equiv META 태그) Beautiful Soup이 문서 내에서 이런 종류의 인코딩을 찾으면 처음부터 문서를 다시 구문 분석하고 새 인코딩을 시도합니다. 인코딩을 명시 적으로 지정하고 해당 인코딩이 실제로 작동 한 경우는 예외입니다. 문서에서 찾은 인코딩은 무시됩니다.
  • 파일의 처음 몇 바이트를보고 스니핑 된 인코딩입니다. 이 단계에서 인코딩이 감지되면 UTF- * 인코딩, EBCDIC 또는 ASCII 중 하나가됩니다.
  • chardet 라이브러리에 의해 인코딩 된 인코딩 ( 설치된 경우)
  • UTF-8
  • 윈도우 -1252

1
chardet참조 주셔서 감사합니다 . 조금 느리지 만 좋은 것 같습니다.
Craig McQueen

17
@Geomorillo : "인코딩 표준"과 같은 것은 없습니다. 텍스트 인코딩은 컴퓨팅만큼 오래되었으며 시간과 필요에 따라 유기적으로 성장했으며 계획되지 않았습니다. "유니 코드"는이 문제를 해결하려는 시도입니다.
nosklo

1
그리고 나쁜 것은 아니지만 모든 것을 고려했습니다. 내가 알고 싶은 것은 열린 텍스트 파일을 어떤 인코딩으로 열 었는지 어떻게 알 수 있습니까?
holdenweb

2
@dumbledad 내가 말한 것은 항상 올바르게 감지하는 것이 불가능하다는 것입니다. 당신이 할 수있는 일은 추측이지만 때로는 실패 할 수 있습니다. 인코딩이 실제로 감지되지 않기 때문에 매번 작동하지 않습니다. 추측하기 위해, 당신은 대답에서 제안한 도구 중 하나를 사용할 수 있습니다
nosklo

1
@ LasseKärkkäinen이 대답의 요점은 인코딩을 정확히 감지하는 것이 불가능하다는 것을 보여주는 것입니다 . 귀하가 제공하는 기능은 귀하의 경우에 맞을 수 있지만 많은 경우에 잘못되었습니다.
nosklo

67

인코딩 작업을위한 또 다른 옵션은 libmagic ( 파일 명령 뒤에있는 코드 )을 사용하는 것입니다. 사용 가능한 파이썬 바인딩이 풍부합니다.

파일 소스 트리에있는 파이썬 바인딩은 python-magic (또는 python3-magic ) 데비안 패키지로 제공됩니다. 다음을 수행하여 파일 인코딩을 결정할 수 있습니다.

import magic

blob = open('unknown-file', 'rb').read()
m = magic.open(magic.MAGIC_MIME_ENCODING)
m.load()
encoding = m.buffer(blob)  # "utf-8" "us-ascii" etc

pypi에도 동일한 이름이지만 호환되지 않는 python-magic pip 패키지가 있습니다 libmagic. 다음을 수행하여 인코딩을 가져올 수도 있습니다.

import magic

blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)

5
libmagic에 대한 실질적인 대안 chardet입니다. 그리고 별개의 패키지에 대한 훌륭한 정보 python-magic! 나는 확실히이 모호성은 많은 사람들을 물린거야
MestreLion

1
file텍스트 파일에서 사람의 언어를 식별하는 데 특히 좋지 않습니다. 다양한 컨테이너 형식을 식별하는 데 탁월하지만 때로는 의미가 무엇인지 알아야합니다 ( "Microsoft Office 문서"는 Outlook 메시지 등을 의미 할 수 있음).
Tripleee

파일 인코딩 미스터리를 관리하는 방법을 찾고이 게시물을 찾았습니다. 불행하게도, 예제 코드를 사용하여, 나는 과거 얻을 수 없습니다 open(): UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte. vim 's에 따른 파일 인코딩 :set fileencodinglatin1입니다.
xtian

선택적 인수를 사용하면 errors='ignore'예제 코드의 출력이 덜 유용 binary합니다.
xtian

2
@xtian 바이너리 모드로 열어야합니다 (예 : open ( "filename.txt", "rb")).
L. Kärkkäinen

31

일부 인코딩 전략은 다음과 같이 맛보십시오.

#!/bin/bash
#
tmpfile=$1
echo '-- info about file file ........'
file -i $tmpfile
enca -g $tmpfile
echo 'recoding ........'
#iconv -f iso-8859-2 -t utf-8 back_test.xml > $tmpfile
#enca -x utf-8 $tmpfile
#enca -g $tmpfile
recode CP1250..UTF-8 $tmpfile

루프 형태로 파일을 열어서 인코딩을 확인하고 싶을 수도 있지만 먼저 파일 크기를 확인해야 할 수도 있습니다.

encodings = ['utf-8', 'windows-1250', 'windows-1252' ...etc]
            for e in encodings:
                try:
                    fh = codecs.open('file.txt', 'r', encoding=e)
                    fh.readlines()
                    fh.seek(0)
                except UnicodeDecodeError:
                    print('got unicode error with %s , trying different encoding' % e)
                else:
                    print('opening the file with encoding:  %s ' % e)
                    break              

당신은 또한 사용할 수 있습니다 io같은 io.open(filepath, 'r', encoding='utf-8')때문에, 더 편리하다, codecs변환하지 않습니다 \n읽기, 쓰기에 자동으로. 여기
Searene

23

다음은 파일이 큰 경우 파일에서 chardet읽는 인코딩 예측 을 액면 값에서 읽고 취하는 예입니다 n_lines.

chardet또한 confidence인코딩 예측의 가능성 (즉, 어떻게 될지 찾지 못했음)을 제공합니다.이 예측은에서 예측과 함께 반환 chardet.predict()되므로 원하는 경우 어떻게 든 작동 할 수 있습니다.

def predict_encoding(file_path, n_lines=20):
    '''Predict a file's encoding using chardet'''
    import chardet

    # Open the file as binary data
    with open(file_path, 'rb') as f:
        # Join binary lines for specified number of lines
        rawdata = b''.join([f.readline() for _ in range(n_lines)])

    return chardet.detect(rawdata)['encoding']

투표권을 얻은 후 이것을보고 이제 첫 번째 행에 많은 데이터가있는 경우이 솔루션이 느려질 수 있음을 알 수 있습니다. 어떤 경우에는 데이터를 다르게 읽는 것이 좋습니다.
ryanjdillon

2
이 기능을 다음과 같이 수정했습니다 def predict_encoding(file_path, n=20): ... skip ... and then rawdata = b''.join([f.read() for _ in range(n)]) . Python 3.6에서이 기능을 사용해 보았으며 "ascii", "cp1252", "utf-8", "unicode"인코딩과 완벽하게 작동했습니다. 따라서 이것은 명백하게 공세입니다.
n158

1
이것은 다양한 형식의 작은 데이터 세트를 처리하는 데 매우 좋습니다. 내 루트 디렉토리에서 이것을 재귀 적으로 테스트했으며 치료처럼 작동했습니다. 고마워 친구.
Datanovice

4
# Function: OpenRead(file)

# A text file can be encoded using:
#   (1) The default operating system code page, Or
#   (2) utf8 with a BOM header
#
#  If a text file is encoded with utf8, and does not have a BOM header,
#  the user can manually add a BOM header to the text file
#  using a text editor such as notepad++, and rerun the python script,
#  otherwise the file is read as a codepage file with the 
#  invalid codepage characters removed

import sys
if int(sys.version[0]) != 3:
    print('Aborted: Python 3.x required')
    sys.exit(1)

def bomType(file):
    """
    returns file encoding string for open() function

    EXAMPLE:
        bom = bomtype(file)
        open(file, encoding=bom, errors='ignore')
    """

    f = open(file, 'rb')
    b = f.read(4)
    f.close()

    if (b[0:3] == b'\xef\xbb\xbf'):
        return "utf8"

    # Python automatically detects endianess if utf-16 bom is present
    # write endianess generally determined by endianess of CPU
    if ((b[0:2] == b'\xfe\xff') or (b[0:2] == b'\xff\xfe')):
        return "utf16"

    if ((b[0:5] == b'\xfe\xff\x00\x00') 
              or (b[0:5] == b'\x00\x00\xff\xfe')):
        return "utf32"

    # If BOM is not provided, then assume its the codepage
    #     used by your operating system
    return "cp1252"
    # For the United States its: cp1252


def OpenRead(file):
    bom = bomType(file)
    return open(file, 'r', encoding=bom, errors='ignore')


#######################
# Testing it
#######################
fout = open("myfile1.txt", "w", encoding="cp1252")
fout.write("* hi there (cp1252)")
fout.close()

fout = open("myfile2.txt", "w", encoding="utf8")
fout.write("\u2022 hi there (utf8)")
fout.close()

# this case is still treated like codepage cp1252
#   (User responsible for making sure that all utf8 files
#   have a BOM header)
fout = open("badboy.txt", "wb")
fout.write(b"hi there.  barf(\x81\x8D\x90\x9D)")
fout.close()

# Read Example file with Bom Detection
fin = OpenRead("myfile1.txt")
L = fin.readline()
print(L)
fin.close()

# Read Example file with Bom Detection
fin = OpenRead("myfile2.txt")
L =fin.readline() 
print(L) #requires QtConsole to view, Cmd.exe is cp1252
fin.close()

# Read CP1252 with a few undefined chars without barfing
fin = OpenRead("badboy.txt")
L =fin.readline() 
print(L)
fin.close()

# Check that bad characters are still in badboy codepage file
fin = open("badboy.txt", "rb")
fin.read(20)
fin.close()

2

귀하의 플랫폼에 따라 linux shell file명령 을 사용하기로 선택했습니다 . Linux 시스템 중 하나에서 독점적으로 실행되는 스크립트에서 사용하기 때문에 이것은 나를 위해 작동합니다.

분명히 이것은 이상적인 솔루션이나 답변이 아니지만 필요에 맞게 수정할 수 있습니다. 제 경우에는 파일이 UTF-8인지 아닌지를 결정하기 만하면됩니다.

import subprocess
file_cmd = ['file', 'test.txt']
p = subprocess.Popen(file_cmd, stdout=subprocess.PIPE)
cmd_output = p.stdout.readlines()
# x will begin with the file type output as is observed using 'file' command
x = cmd_output[0].split(": ")[1]
return x.startswith('UTF-8')

새로운 프로세스를 수행 할 필요가 없습니다. 파이썬 코드는 이미 프로세스 내에서 실행되며 새로운 프로세스를로드하는 오버 헤드없이 적절한 시스템 함수 자체를 호출 할 수 있습니다.
vdboor

2

도움이 될 수 있습니다.

from bs4 import UnicodeDammit
with open('automate_data/billboard.csv', 'rb') as file:
   content = file.read()

suggestion = UnicodeDammit(content)
suggestion.original_encoding
#'iso-8859-1'

1

일반적으로 텍스트 파일의 인코딩을 결정하는 것은 일반적으로 불가능합니다. 따라서 아닙니다. 표준 파이썬 라이브러리는 없습니다.

텍스트 파일에 대한보다 구체적인 지식이 있으면 (예 : XML) 라이브러리 함수가있을 수 있습니다.


1

파일의 일부 내용을 알고 있으면 여러 인코딩으로 파일을 디코딩하여 누락 된 부분을 확인할 수 있습니다. 일반적으로 텍스트 파일은 텍스트 파일이고 어리석기 때문에 방법이 없습니다.)


1

이 사이트에는 ascii 인식, boms로 인코딩 및 utf8 no bom을위한 Python 코드가 있습니다 ( https://unicodebook.readthedocs.io/guess_encoding.html) . 바이트 배열 (데이터)로 파일 읽기 : http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array . 다음은 예입니다. 나는 osx에있다.

#!/usr/bin/python                                                                                                  

import sys

def isUTF8(data):
    try:
        decoded = data.decode('UTF-8')
    except UnicodeDecodeError:
        return False
    else:
        for ch in decoded:
            if 0xD800 <= ord(ch) <= 0xDFFF:
                return False
        return True

def get_bytes_from_file(filename):
    return open(filename, "rb").read()

filename = sys.argv[1]
data = get_bytes_from_file(filename)
result = isUTF8(data)
print(result)


PS /Users/js> ./isutf8.py hi.txt                                                                                     
True

솔루션에 대한 링크는 환영하지만 답변없이 유용한 답변을 얻으십시오 . 링크 주위에 컨텍스트를 추가 하여 동료 사용자가 그 이유와 그 이유를 파악한 다음 페이지의 가장 관련성이 높은 부분을 인용하십시오. 대상 페이지를 사용할 수없는 경우 다시 연결 링크에 불과한 답변은 삭제 될 수 있습니다.
double-beep
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.