Programing

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

lottogame 2020. 5. 9. 09:07
반응형

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


인코딩 된 텍스트를 받았지만 어떤 문자 집합이 사용되었는지 알 수 없습니다. 파이썬을 사용하여 텍스트 파일의 인코딩을 결정하는 방법이 있습니까? C #을 처리 하는 텍스트 파일의 인코딩 / 코드 페이지를 어떻게 감지합니까 ?


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

(chardet FAQ에서 :)

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

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

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

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

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

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

import magic

blob = open('unknown-file').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').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)

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

#!/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              

Here is an example of reading and taking at face value a chardet encoding prediction, reading n_lines from the file in the event it is large.

chardet also gives you a probability (i.e. confidence) of it's encoding prediction (haven't looked how they come up with that), which is returned with its prediction from chardet.predict(), so you could work that in somehow if you like.

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']

# 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()

Depending on your platform, I just opt to use the linux shell file command. This works for me since I am using it in a script that exclusively runs on one of our linux machines.

Obviously this isn't an ideal solution or answer, but it could be modified to fit your needs. In my case I just need to determine whether a file is UTF-8 or not.

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')

It is, in principle, impossible to determine the encoding of a text file, in the general case. So no, there is no standard Python library to do that for you.

If you have more specific knowledge about the text file (e.g. that it is XML), there might be library functions.


If you know the some content of the file you can try to decode it with several encoding and see which is missing. In general there is no way since a text file is a text file and those are stupid ;)


This site has python code for recognizing ascii, encoding with boms, and utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html. Read file into byte array (data): http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array. Here's an example. I'm in 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

참고URL : https://stackoverflow.com/questions/436220/how-to-determine-the-encoding-of-text

반응형