Jak określić kodowanie tekstu?

Otrzymałem jakiś tekst, który jest zakodowany, ale nie wiem, jakiego charsetu użyto. Czy istnieje sposób na określenie kodowania pliku tekstowego za pomocą Pythona? Jak mogę wykryć kodowanie / kodowanie pliku tekstowego w C#.

Author: martineau, 2009-01-12

10 answers

EDIT: chardet wydaje się być niewzruszony, ale większość odpowiedzi ma zastosowanie. Sprawdź https://pypi.org/project/charset-normalizer / dla alternatywy

Prawidłowe wykrycie kodowania wszystkich czasów jest niemożliwe .

(z CHARDET FAQ:)

Jednak niektóre kodowania są zoptymalizowane dla poszczególnych języków i języków nie są przypadkowe. Some character sekwencje pojawiają się cały czas, podczas gdy inne sekwencje nie mają sensu. A osoba biegle władająca językiem angielskim, która otwiera a gazeta i znaleziska " txzqJv 2!dasd0a QqdKjvz " natychmiast rozpozna, że to nie jest angielski (mimo że jest składa się w całości z liter angielskich). Studiując wiele "typowych" tekstów, a algorytm komputerowy może symulować to rodzaj płynności i sprawiają, że wykształcony Odgadnij język tekstu.

Istnieje biblioteka chardet, która używa tego badania do wykrywania kodowania. chardet jest portem kodu automatycznego wykrywania w Mozilli.

Możesz również użyć UnicodeDammit . Spróbuje następujących metod:

  • kodowanie Odkryte w samym dokumencie: na przykład w deklaracji XML lub (w przypadku dokumentów HTML) meta tag http-equiv. Jeśli Beautiful Soup znajdzie tego rodzaju kodowanie w dokumencie, przetworzy dokument ponownie Od początku i spróbuje nowego kodowania. Jedynym wyjątkiem jest, jeśli jawnie podałeś kodowanie, A kodowanie faktycznie działało: wtedy zignoruje ono każde kodowanie, które znajdzie w dokumencie.
  • kodowanie sniffed patrząc na kilka pierwszych bajtów pliku. Jeśli na tym etapie zostanie wykryte kodowanie, będzie to jedno z kodowań UTF -*, EBCDIC lub ASCII.
  • kodowanie wąchane przez bibliotekę chardet , Jeśli masz ją zainstalowaną.
  • UTF-8
  • Windows-1252
 240
Author: nosklo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-29 22:11:18

Inną opcją do rozpracowania kodowania jest użycie libmagic (czyli kod za file command). Istnieje obfite dostępne wiązania Pythona.

Wiązania Pythona, które żyją w drzewie źródeł plików, są dostępne jako python-Magia (lub python3-Magia ) pakiet Debiana. Może określić kodowanie pliku wykonując:

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

Istnieje identycznie nazwany, ale niezgodny, python-magic Pakiet pip na pypi, który również używa libmagic. Może również uzyskać kodowanie, wykonując:

import magic

blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
 76
Author: Hamish Downer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-20 16:45:26

Niektóre strategie kodowania, proszę odkomentować do smaku:

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

Możesz sprawdzić kodowanie, otwierając i czytając plik w postaci pętli... ale być może będziesz musiał najpierw sprawdzić rozmiar pliku:

#PYTHON
encodings = ['utf-8', 'windows-1250', 'windows-1252'] # add more
            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              
 35
Author: zzart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-27 12:19:34

Oto przykład odczytu i wykonania przy wartości nominalnej prognozy kodowania chardet, odczytu n_lines z pliku w przypadku, gdy jest on duży.

chardet daje również prawdopodobieństwo (tj. confidence) jego przewidywania kodowania( nie wyglądałem, jak na to wpadli), które jest zwracane wraz z jego przewidywaniem z chardet.predict(), więc możesz to jakoś sprawdzić, jeśli chcesz.

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']
 30
Author: ryanjdillon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-18 13:01:49

To może być pomocne

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'
 6
Author: richinex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-25 23:54:13
# 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()
 5
Author: Bimo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 14:06:49

W zależności od platformy, po prostu wybieram polecenie powłoki Linuksa file. To działa dla mnie, ponieważ używam go w skrypcie, który działa wyłącznie na jednym z naszych maszyn linuksowych.

Oczywiście nie jest to idealne rozwiązanie lub odpowiedź, ale można je zmodyfikować do własnych potrzeb. W moim przypadku muszę tylko ustalić, czy plik jest UTF-8, czy nie.

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')
 2
Author: MikeD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-22 17:04:38

Zasadniczo niemożliwe jest określenie kodowania pliku tekstowego, w ogólnym przypadku. Więc nie, nie ma standardowej biblioteki Pythona, która zrobiłaby to za Ciebie.

Jeśli masz bardziej szczegółową wiedzę na temat pliku tekstowego (np. że jest to XML), mogą istnieć funkcje biblioteczne.

 1
Author: Martin v. Löwis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-12 17:32:27

Jeśli znasz jakąś zawartość pliku, możesz spróbować go dekodować kilkoma kodowaniami i zobaczyć, którego brakuje. Generalnie nie ma mowy bo plik tekstowy to plik tekstowy a te są głupie;)

 1
Author: Martin Thurau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-12 17:36:42

Ta strona ma kod Pythona do rozpoznawania ascii, kodowania za pomocą BOM i utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html . odczyt pliku do tablicy bajtów (dane): http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array. Oto przykład. Jestem w 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
 1
Author: js2010,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-12 14:46:44