web-dev-qa-db-ja.com

テキストのエンコーディングを決定する方法は?

エンコードされたテキストを受け取りましたが、どの文字セットが使用されたかわかりません。 Pythonを使用してテキストファイルのエンコーディングを決定する方法はありますか? テキストファイルのエンコード/コードページを検出する方法 C#を扱います。

186
Nope

エンコーディングを常に正しく検出することはimpossibleです。

(chardet FAQから:)

ただし、一部のエンコードは特定の言語向けに最適化されており、言語はランダムではありません。一部の文字シーケンスは常にポップアップしますが、他のシーケンスは意味がありません。英語に堪能で、新聞を開いて「txzqJv 2!dasd0a QqdKjvz」を見つけた人は、それが英語ではないことを即座に認識します(英語の文字だけで構成されている場合でも)。多くの「典型的な」テキストを研究することにより、コンピューターアルゴリズムはこの種の流simulateさをシミュレートし、テキストの言語について経験に基づいた推測を行うことができます。

その研究を使用してエンコードを検出しようとする chardet ライブラリがあります。 chardetは、Mozillaの自動検出コードの移植版です。

nicodeDammit を使用することもできます。次の方法を試みます。

  • 文書自体で検出されたエンコード:たとえば、XML宣言または(HTML文書の場合)http-equiv METAタグ。 Beautiful Soupがドキュメント内でこの種のエンコーディングを見つけると、ドキュメントを最初から再度解析し、新しいエンコーディングを試してみます。唯一の例外は、エンコードを明示的に指定し、そのエンコードが実際に機能した場合です。ドキュメントで見つかったエンコードは無視されます。
  • ファイルの最初の数バイトを調べることで盗聴されたエンコード。この段階でエンコードが検出された場合、UTF- *エンコード、EBCDIC、またはASCIIのいずれかになります。
  • chardet ライブラリ(インストールされている場合)によってスニッフィングされたエンコード。
  • UTF-8
  • Windows-1252
193
nosklo

エンコードを解決する別のオプションは、 libmagicfile コマンドの背後にあるコード)を使用することです。 pythonバインディングが豊富に用意されています。

ファイルソースツリーにあるpythonバインディングは、 python-magic (または python3-magic )debianパッケージとして利用できます。以下を実行することにより、ファイルのエンコードを判別できます。

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には、libmagicも使用する同じ名前の、互換性のない python-magic pipパッケージがあります。また、以下を実行することにより、エンコードを取得できます。

import magic

blob = open('unknown-file').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
49
Hamish Downer

いくつかのエンコーディング戦略は、コメントを外してください:

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

以下は、額面でchardetエンコーディングの予測を読み取り、取得し、ファイルが大きい場合にファイルからn_linesを読み取る例です。

chardetは、エンコード予測の確率(つまり、confidence)も提供します(__VARIABLE)_は、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']
16
ryanjdillon
# 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()
3
Bill Moore

プラットフォームに応じて、Linux Shell fileコマンドを使用することを選択します。これは、Linuxマシンの1つで排他的に実行されるスクリプトで使用しているため、私にとっては有効です。

明らかにこれは理想的な解決策や答えではありませんが、ニーズに合わせて変更することができます。私の場合、ファイルが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')
1
MikeD

一般的に、テキストファイルのエンコーディングを決定することは原則として不可能です。そのため、標準のPythonライブラリはありません。

テキストファイルについてより具体的な知識がある場合(たとえば、XMLである場合)、ライブラリ関数がある可能性があります。

0

ファイルの内容がわかっている場合は、いくつかのエンコードを使用してデコードして、どれが欠落しているかを確認できます。一般的に、テキストファイルはテキストファイルであり、それらは愚かです;)

0
Martin Thurau