Otrzymałem zakodowany tekst, ale nie wiem, jaki zestaw znaków został użyty. Czy istnieje sposób na określenie kodowania pliku tekstowego za pomocą Pythona? Jak mogę wykryć kodowanie / stronę kodową pliku tekstowego zajmującego się C #.
Otrzymałem zakodowany tekst, ale nie wiem, jaki zestaw znaków został użyty. Czy istnieje sposób na określenie kodowania pliku tekstowego za pomocą Pythona? Jak mogę wykryć kodowanie / stronę kodową pliku tekstowego zajmującego się C #.
Odpowiedzi:
Prawidłowe wykrycie kodowania przez cały czas jest niemożliwe .
(Z FAQ chardet :)
Jednak niektóre kodowania są zoptymalizowane dla określonych języków, a języki nie są losowe. Niektóre sekwencje postaci pojawiają się cały czas, podczas gdy inne sekwencje nie mają sensu. Osoba biegła w języku angielskim, która otworzy gazetę i znajdzie „txzqJv 2! Dasd0a QqdKjvz”, natychmiast rozpozna, że to nie jest angielski (nawet jeśli składa się wyłącznie z angielskich liter). Studiując wiele „typowych” tekstów, algorytm komputerowy może symulować tego rodzaju płynność i zgrabnie zgadywać o języku tekstu.
Istnieje biblioteka chardet, która wykorzystuje to badanie do próby wykrycia kodowania. chardet to port kodu automatycznego wykrywania w Mozilli.
Możesz także użyć UnicodeDammit . Spróbuje następujących metod:
Inną opcją do opracowania kodowania jest użycie libmagic (czyli kodu stojącego za poleceniem file ). Dostępnych jest wiele powiązań Pythona.
Powiązania Pythona, które istnieją w drzewie źródeł plików, są dostępne jako pakiet debian python-magic (lub python3-magic ). 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 pipi o identycznej nazwie, ale niekompatybilny, python-magic pip, 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)
libmagic
jest rzeczywiście realną alternatywą dla chardet
. I świetne informacje o nazwanych pakietach python-magic
! Jestem pewien, że ta dwuznaczność gryzie wielu ludzi
file
nie jest szczególnie dobry w rozpoznawaniu ludzkiego języka w plikach tekstowych. Doskonale nadaje się do identyfikowania różnych formatów kontenerów, chociaż czasami musisz wiedzieć, co to znaczy („dokument Microsoft Office” może oznaczać wiadomość programu Outlook itp.).
open()
: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte
. Kodowanie plików według vima :set fileencoding
to latin1
.
errors='ignore'
, wynik kodu przykładowego jest mniej pomocny binary
.
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że chcesz sprawdzić kodowanie, otwierając i odczytując plik w formie pętli ... ale może być konieczne najpierw sprawdzenie rozmiaru pliku:
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
Oto przykład odczytu i wzięcia pod uwagę chardet
prognozy kodowania, czytania n_lines
z pliku w przypadku, gdy jest on duży.
chardet
daje również prawdopodobieństwo (tj. confidence
) przewidywania kodowania (nie spojrzałem, jak oni to wymyślili), które jest zwracane wraz z jego przewidywaniem chardet.predict()
, więc możesz to w jakiś sposób wykorzystać, 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']
def predict_encoding(file_path, n=20): ... skip ... and then rawdata = b''.join([f.read() for _ in range(n)])
wypróbowałem tę funkcję w Pythonie 3.6, działał doskonale z kodowaniem „ascii”, „cp1252”, „utf-8”, „Unicode”. To zdecydowanie jest pozytywne.
# 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()
W zależności od twojej platformy, po prostu wybrałem file
polecenie powłoki Linux . Działa to dla mnie, ponieważ używam go w skrypcie, który działa wyłącznie na jednym z naszych komputerów z systemem Linux.
Oczywiście nie jest to idealne rozwiązanie ani odpowiedź, ale można je zmodyfikować w celu dopasowania do Twoich potrzeb. W moim przypadku muszę tylko ustalić, czy plik to 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')
Zasadniczo niemożliwe jest określenie kodowania pliku tekstowego, w ogólnym przypadku. Więc nie, nie ma standardowej biblioteki Pythona, która mogłaby to dla Ciebie zrobić.
Jeśli masz bardziej szczegółową wiedzę na temat pliku tekstowego (np. Że jest to XML), mogą istnieć funkcje biblioteczne.
Jeśli znasz pewną zawartość pliku, możesz spróbować go zdekodować za pomocą kilku kodowań i zobaczyć, którego brakuje. W ogóle nie ma mowy, ponieważ plik tekstowy jest plikiem tekstowym, a te są głupie;)
Ta strona ma kod Pythona do rozpoznawania ascii, kodowania za pomocą boms i utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html . Wczytaj plik 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
chardet
referencje. Wydaje się być dobry, choć nieco powolny.