Я получил кодированный текст, но я не знаю, какая кодировка использовалась. Есть ли способ определить кодировку текстового файла с помощью Python? Как я могу определить кодировку / кодовую страницу текстового файла имеет дело с C#.






Определить кодировку текстового файла в общем случае в принципе невозможно. Так что нет, стандартной библиотеки Python для этого не существует.
Если у вас есть более конкретные знания о текстовом файле (например, что это XML), могут быть библиотечные функции.
Если вам известно какое-то содержимое файла, вы можете попытаться декодировать его с помощью нескольких кодировок и посмотреть, какая из них отсутствует. В общем, нет никакого способа, так как текстовый файл - это текстовый файл, а это глупо;)
Обновлено: chardet, похоже, не поддерживается, но большая часть ответа применима. Проверьте https://pypi.org/project/charset-normalizer/ для альтернативы
Правильное определение кодировки всегда - невозможно.
(Из FAQ по chardet :)
However, some encodings are optimized for specific languages, and languages are not random. Some character sequences pop up all the time, while other sequences make no sense. A person fluent in English who opens a newspaper and finds “txzqJv 2!dasd0a QqdKjvz” will instantly recognize that that isn't English (even though it is composed entirely of English letters). By studying lots of “typical” text, a computer algorithm can simulate this kind of fluency and make an educated guess about a text's language.
Существует библиотека Chardet, которая использует это исследование, чтобы попытаться обнаружить кодировку. chardet - это порт кода автоопределения в Mozilla.
Вы также можете использовать Юникод. Он попробует следующие методы:
Не удавалось все время определять кодировку ... разве это не ошибка стандарта кодирования? Разве это не должно быть всегда предсказуемо?
@Geomorillo: Не существует такой вещи, как «стандарт кодирования». Кодирование текста такое же старое, как и компьютерные технологии, оно органично росло со временем и потребностями, это не планировалось. «Юникод» - это попытка исправить это.
И неплохой, учитывая все обстоятельства. Я хотел бы знать, как мне узнать, с какой кодировкой был открыт открытый текстовый файл?
Меня это смущает. У меня есть текстовый файл, который я с трудом читал на Python, поэтому я открыл его в Visual Studio Code. В нижней части окна результирующего файла написано «UTF-16 LE». Когда вы замечаете, что это невозможно, означает ли это, что такие инструменты, как VSCode, тоже выйдут из строя?
@dumbledad я сказал, что правильно определить все время невозможно. Все, что вы можете сделать, это предположить, но иногда это может не получиться, это не сработает каждый раз из-за того, что кодировки не обнаруживаются. Чтобы сделать предположение, вы можете использовать один из инструментов, которые я предложил в ответе.
chardet имеет действительно хороший интерфейс командной строки, я не уверен насчет вашего варианта использования, для меня я действительно просто пытался угадать кодировку файла на лету, а не использовать это в скрипте или чем-то еще. чтобы использовать параметр CLI (после pip install chardet) $ chardet filename, и вы можете использовать предполагаемую кодировку для кодирования вашего текстового файла в другие параметры, используя такие инструменты, как iconv.
Мне бы очень понравился chardet, но с тех пор, как была добавлена поддержка турецкого языка, цифры были искажены так, что теперь он угадывает турецкий язык для слишком большого количества файлов, с которыми я сталкивался. Настолько, что мне пришлось избавиться от chardet.
Видимо cchardet быстрее, но требует cython.
Удивительно, что ни одно из ранее существовавших решений не помогло, но простая функция подойдет для большинства типичных случаев (и может быть настроена для ваших местных нужд): paste.zi.fi/p/decode.py/view
@ LasseKärkkäinen цель этого ответа - показать, что правильное определение кодировки - это невозможно; функция, которую вы предоставляете, может правильно угадать для вашего случая, но во многих случаях она неверна.
@nosklo Совершенно верно; поэтому в комментарии говорится о 8-битных догадках. Однако следует использовать разумные приоритеты, и теперь Шардет слишком отдает предпочтение турецкому пути. Паста демонстрирует явные проблемы с chardet, которые не могут быть оправданы двусмысленностью (потому что \ x81 не существует в "обнаруженной" кодировке и потому что UTF-8 всегда должен быть первым выбором, когда он подходит).
Вы можете добавить более свежий кодировка-нормализатор
Некоторые стратегии кодирования, пожалуйста, раскомментируйте по вкусу:
#!/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
Вы можете проверить кодировку, открыв и прочитав файл в виде цикла ... но вам может потребоваться сначала проверить размер файла:
#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
Вы также можете использовать io, например io.open(filepath, 'r', encoding='utf-8'), что более удобно, потому что codecs не конвертирует \n автоматически при чтении и записи. Подробнее о ЗДЕСЬ
Другой вариант отработки кодировки - использовать libmagic (код, стоящий за Команда файл). Есть множество Доступны привязки python.
Привязки python, которые живут в дереве исходных файлов файлов, доступны как питон-магия (или python3-magic) пакет debian. Он может определить кодировку файла, выполнив:
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
На pypi есть одноименный, но несовместимый пакет pip питон-магия, который также использует 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.
@xtian Вам нужно открыть в двоичном режиме, т.е. open ("filename.txt", "rb").
chardet не работает с iso-8859-1 (распространенный формат файлов Windows), но работает отлично! libmagic кажется лучшим решением этой проблемы.
второй решил мою проблему. И я должен использовать blob = open ("unknown-file", "rb"). Read (), как сказал Л. Кярккяйнен.
Существует также пакет python-magic-bin, который имеет двоичные файлы и работает в Windows: github.com/julian-r/python-magic Этот пакет вернул двоичный код для кодировки файла .docx, в то время как UnicodeDammit вернул utf-8, а chardet вернул None. В этом случае лучше всего выглядит bs4 (UnicodeDammit).
# 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()
В зависимости от вашей платформы я просто использую команду file оболочки linux. У меня это работает, так как я использую его в скрипте, который работает исключительно на одной из наших 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 уже выполняется внутри процесса и может сам вызывать нужные системные функции без дополнительных затрат на загрузку нового процесса.
Вот пример чтения и принятия за чистую монету предсказания кодирования 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». Так что это определенно положительный голос.
это очень хорошо для обработки небольших наборов данных с различными форматами. Протестировал это рекурсивно в моем корневом каталоге, и он работал как удовольствие. Спасибо дружище.
Я не очень знаком с чтением данных на байтовом уровне. @ n158, есть ли шанс, что можно перестать читать байты в середине символа и запутать chardet?
На этом сайте есть код 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
Ссылка на решение приветствуется, но убедитесь, что ваш ответ полезен и без нее: добавить контекст вокруг ссылки, чтобы ваши коллеги-пользователи имели некоторое представление о том, что это такое и почему оно есть, а затем процитируйте наиболее релевантную часть страницы, на которую вы ссылаетесь. если целевая страница недоступна. Ответы, которые представляют собой не более чем ссылку, могут быть удалены.
Это может быть полезно
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'
Спасибо за ссылку на
chardet. Вроде неплохо, хотя немного медленнее.