Ho ricevuto del testo codificato, ma non so quale set di caratteri sia stato utilizzato. C'è un modo per determinare la codifica di un file di testo usando Python? Come posso rilevare la codifica / codepage di un file di testo che si occupa di C #.
Ho ricevuto del testo codificato, ma non so quale set di caratteri sia stato utilizzato. C'è un modo per determinare la codifica di un file di testo usando Python? Come posso rilevare la codifica / codepage di un file di testo che si occupa di C #.
Risposte:
Rilevare correttamente la codifica in ogni momento è impossibile .
(Da Chardet FAQ :)
Tuttavia, alcune codifiche sono ottimizzate per lingue specifiche e le lingue non sono casuali. Alcune sequenze di personaggi compaiono continuamente, mentre altre sequenze non hanno senso. Una persona fluente in inglese che apre un giornale e trova "txzqJv 2! Dasd0a QqdKjvz" riconoscerà immediatamente che non è inglese (anche se è composto interamente da lettere inglesi). Studiando un sacco di testo "tipico", un algoritmo informatico può simulare questo tipo di fluidità e fare un'ipotesi educata sulla lingua di un testo.
C'è la libreria chardet che usa quello studio per provare a rilevare la codifica. chardet è una porta del codice di rilevamento automatico in Mozilla.
Puoi anche usare UnicodeDammit . Proverà i seguenti metodi:
Un'altra opzione per elaborare la codifica è usare libmagic (che è il codice dietro il comando file ). È disponibile una profusione di attacchi in pitone.
I collegamenti python che vivono nell'albero dei file sorgente sono disponibili come pacchetto debian python-magic (o python3-magic ). Può determinare la codifica di un file facendo:
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
Esiste un pacchetto pip python-magic identico, ma incompatibile, su pypi che usa anche libmagic
. Può anche ottenere la codifica, facendo:
import magic
blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
libmagic
è davvero una valida alternativa a chardet
. E ottime informazioni sui pacchetti distinti chiamati python-magic
! Sono sicuro che questa ambiguità morde molte persone
file
non è particolarmente bravo a identificare il linguaggio umano nei file di testo. È eccellente per identificare vari formati di container, anche se a volte devi sapere cosa significa ("documento di Microsoft Office" potrebbe significare un messaggio di Outlook, ecc.).
open()
: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte
. La codifica dei file secondo vim's :set fileencoding
è latin1
.
errors='ignore'
, l'output del codice di esempio è meno utile binary
.
Alcune strategie di codifica, ti preghiamo di commentare a piacere:
#!/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
Potresti voler controllare la codifica aprendo e leggendo il file in una forma di ciclo ... ma potresti dover prima controllare la dimensione del file:
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
Ecco un esempio di lettura e presa al valore nominale di una chardet
previsione di codifica, lettura n_lines
dal file nel caso in cui sia grande.
chardet
ti dà anche una probabilità (cioè confidence
) della sua previsione di codifica (non ho visto come ne escono), che viene restituito con la sua previsione da chardet.predict()
, quindi potresti farlo in qualche modo se ti piace.
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)])
ho provato questa funzione su Python 3.6, ha funzionato perfettamente con le codifiche "ascii", "cp1252", "utf-8", "unicode". Quindi questo è decisamente positivo.
# 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()
A seconda della tua piattaforma, scelgo di usare il file
comando shell linux . Questo funziona per me dal momento che lo sto usando in uno script che gira esclusivamente su una delle nostre macchine Linux.
Ovviamente questa non è una soluzione o una risposta ideale, ma potrebbe essere modificata in base alle proprie esigenze. Nel mio caso, devo solo determinare se un file è UTF-8 o meno.
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')
In linea di principio è impossibile determinare la codifica di un file di testo, nel caso generale. Quindi no, non esiste una libreria Python standard per farlo.
Se si dispone di conoscenze più specifiche sul file di testo (ad esempio che si tratta di XML), potrebbero esserci funzioni di libreria.
Se conosci il contenuto del file, puoi provare a decodificarlo con diverse codifiche e vedere quale manca. In generale non c'è modo poiché un file di testo è un file di testo e quelli sono stupidi;)
Questo sito ha un codice Python per il riconoscimento di ASCII, la codifica con boms e utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html . Leggi il file nell'array di byte (dati): http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array . Ecco un esempio Sono 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
chardet
riferimento. Sembra buono, anche se un po 'lento.