Я отримав текст, який закодований, але я не знаю, яку діаграму використовували. Чи є спосіб визначити кодування текстового файлу за допомогою Python? Як я можу виявити кодування / кодування сторінки текстового файлу, що стосується C #.
Я отримав текст, який закодований, але я не знаю, яку діаграму використовували. Чи є спосіб визначити кодування текстового файлу за допомогою Python? Як я можу виявити кодування / кодування сторінки текстового файлу, що стосується C #.
Відповіді:
Правильно виявити кодування весь час неможливо .
(З FAQ Шардета :)
Однак деякі кодування оптимізовані для конкретних мов, а мови не є випадковими. Деякі послідовності символів спливають весь час, тоді як інші послідовності не мають сенсу. Людина, яка вільно розмовляє англійською мовою, яка відкриває газету і знаходить “txzqJv 2! Dasd0a QqdKjvz”, миттєво визнає, що це не англійська мова (навіть якщо вона складається повністю з англійських букв). Вивчаючи багато «типового» тексту, комп’ютерний алгоритм може імітувати подібний рівень вільності та робити зрозумілі здогадки про мову тексту.
Існує бібліотека chardet, яка використовує це дослідження, щоб спробувати виявити кодування. chardet - порт коду автоматичного виявлення в Mozilla.
Ви також можете використовувати UnicodeDammit . Буде спробувати наступні методи:
Іншим варіантом розробки кодування є використання libmagic (що є кодом, що стоїть за командною файлом ). Існує велика кількість зв'язків пітона.
Прив'язки python, що живуть у дереві джерела файлів, доступні у вигляді пакету debian python-magic (або python3-magic ). Він може визначити кодування файлу, виконавши:
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
Існує ідентично названий, але несумісний пакет python-magic pip на pypi, який також використовує libmagic
. Він також може отримати кодування, виконавши:
import magic
blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
libmagic
дійсно є життєздатною альтернативою chardet
. І чудова інформація про відомі пакети python-magic
! Я впевнений, що ця неоднозначність кусає багатьох людей
file
не особливо добре розпізнавати людську мову в текстових файлах. Він відмінно підходить для виявлення різних форматів контейнерів, хоча іноді доводиться знати, що це означає ("документ Microsoft Office" може означати повідомлення Outlook тощо).
open()
: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte
. Кодування файлу відповідно до vim's :set fileencoding
є latin1
.
errors='ignore'
, вихід з прикладу коду є менш корисним binary
.
Деякі стратегії кодування, будь ласка, залиште на смак:
#!/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
Ось приклад читання та прийняття за номінальною вартістю chardet
прогнозування кодування, зчитування n_lines
з файлу, якщо він великий.
chardet
також дає вам ймовірність (тобто confidence
) прогнозування кодування (не дивилися, як вони придумують це), яке повертається з його передбаченням 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']
def predict_encoding(file_path, n=20): ... skip ... and then rawdata = b''.join([f.read() for _ in range(n)])
Спробував цю функцію на Python 3.6, прекрасно працював з кодуваннями "ascii", "cp1252", "utf-8", "unicode". Тож це, безумовно, є актуальним.
# 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()
Залежно від вашої платформи, я просто вирішую використовувати команду linux shell file
. Це працює для мене, оскільки я використовую його в сценарії, який ексклюзивно працює на одній з наших машин Linux.
Очевидно, що це не ідеальне рішення чи відповідь, але його можна змінити відповідно до ваших потреб. У моєму випадку мені просто потрібно визначити, чи є файл 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')
В принципі, неможливо визначити кодування текстового файлу, в загальному випадку. Так ні, немає стандартної бібліотеки Python, яка б це зробила для вас.
Якщо ви маєте більш конкретні знання про текстовий файл (наприклад, що це XML), можливо, існують бібліотечні функції.
Якщо вам відомий деякий вміст файлу, ви можете спробувати розшифрувати його за допомогою декількох кодувань і побачити, якого немає. Взагалі немає можливості, оскільки текстовий файл - це текстовий файл, а це дурні;)
На цьому веб-сайті є код python для розпізнавання ascii, кодування з boms та utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html . Прочитайте файл у байтовому масиві (дані): http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array . Ось приклад. Я в 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
довідку. Здається добре, хоча трохи повільно.