Как узнать кодировку файла python
Перейти к содержимому

Как узнать кодировку файла python

  • автор:

Модуль chardet в Python, определение кодировки

Когда мы думаем о тексте, то представляем слова и буквы, которые видим на экране компьютера. Но компьютеры не работают с буквами и символами. Они имеют дело с битами и байтами. Каждый фрагмент текста, который выводится на экране, на самом деле хранится в определенной кодировке символов. Существует множество различных кодировок, некоторые из которых оптимизированы для определенных языков, таких как русский, китайский или английский, а другие могут использоваться для нескольких языков. Грубо говоря, кодировка символов обеспечивает соответствие между тем, что мы видим на экране, и тем, что компьютер фактически хранит в памяти и на диске.

Модуль chardet , это автоматический детектор кодировки текста и является портом кода автоопределения в Mozilla. Этот модуль поможет определить кодировку символов, если вдруг на экране появятся «кракозябры«.

Модуль chardet отлично поддерживает и определяет русские кодировки: KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251(Cyrillic)

Установка модуля chardet в виртуальное окружение.

# создаем виртуальное окружение, если нет $ python3 -m venv .venv --prompt VirtualEnv # активируем виртуальное окружение $ source .venv/bin/activate # ставим модуль chardet (VirtualEnv):~$ python -m pip install -U chardet

Примеры автоматического определения кодировки символов:

Самый простой способ автоматически определить кодировку — это использовать функцию обнаружения detect() модуля chardet .

>>> import urllib.request, chardet >>> rawdata = urllib.request.urlopen('http://yandex.ru/').read() >>> chardet.detect(rawdata) # >>> rawdata = urllib.request.urlopen('https://www.zeit.de/index').read() >>> chardet.detect(rawdata) #

Расширенное использование модуля chardet .

Если имеется большой объем текста/данных, то можно вызывать обнаружение кодировки постепенно. Как только модуль будет достаточно уверен в своих результатах, он остановится.

Для такого поведения необходимо создать объект UniversalDetector(), затем повторно вызывать его метод подачи .feed() с каждым блоком текста. Если созданный детектор достигнет минимального порога достоверности, он установит для Detector.done значение True.

В конце работы детектора необходимо вызвать Detector.close() , который выполнит некоторые окончательные вычисления в случае, если детектор не достиг минимального порога достоверности.

import urllib.request from chardet.universaldetector import UniversalDetector usock = urllib.request.urlopen('https://www.zeit.de/index') # создаем детектор detector = UniversalDetector() for line in usock.readlines(): # скармливаем детектору строки detector.feed(line) if detector.done: # если детектор определил # кодировку, то прерываем цикл break # закрываем детектор detector.close() # закрываем соединение с сайтом usock.close() print(detector.result) #

Пример определения кодировки нескольких файлов.

Для определения кодировки текстовых файлов, их необходимо открывать в режиме чтения байтов: more=’rb’

import glob from chardet.universaldetector import UniversalDetector # создаем детектор detector = UniversalDetector() for filename in glob.glob('*.xml'): print(filename.ljust(60), end='') # сбрасываем детектор # в исходное состояние detector.reset() # проходимся по строкам очередного # файла в режиме 'rb' for line in open(filename, 'rb'): detector.feed(line) if detector.done: break detector.close() print(detector.result) 

Кодировки в python

В python есть 2 объекта работающими с текстом: unicode и str, объект unicode хранит символы в формате (кодировке) unicode, объект str является набором байт/символов в которых python хранит остальные кодировки (utf8, cp1251, cp866, koi8-r и др).

Кодировку unicode можно считать рабочей кодировкой питона т.к. она предназначена для её использования в самом скрипте — для разных операций над строками.
Внешняя кодировка (объект str) предназначена для хранения и передачи текстовой информации вне скрипта, например для сохранения в файл или передачи по сети. Поэтому в данной статье я её назвал внешней. Самой используемой кодировкой в мире является utf8 и число приложений переходящих на эту кодировку растет каждый день, таким образом превращаясь в «стандарт». Эта кодировка хороша тем что для хранения текста она занимает оптимальное кол-во памяти и с помощью её можно закодировать почти все языки мира ( в отличие от cp1251 и подобных однобайтовых кодировок). Поэтому рекомендуется везде использовать utf8, и при написании скриптов.

Использование

Скрипт питона, в самом начале скрипта указываем кодировку файла и сохраняем в ней файл

# coding: utf8 
# -*- coding: utf-8 -*- 

для того что-бы интерпретатор python понял в какой кодировке файл

Строки в скрипте
Строки в скрипте хранятся байтами, от кавычки до кавычки:

print 'Привет' 

= 6 байт при cp1251
= 12 байт при utf8

Если перед строкой добавить символ u, то при запуске скрипта, эта байтовая строка будет декодирована в unicode из кодировки указанной в начале:

# coding:utf8 print u'Привет' 

и если кодировка содержимого в файле отличается от указанной, то в строке могут быть «битые символы»

Загрузка и сохранение файла

# coding: utf8 # Загружаем файл с кодировкай utf8 text = open('file.txt','r').read() # Декодируем из utf8 в unicode - из внешней в рабочую text = text.decode('utf8') # Работаем с текстом text += text # Кодируем тест из unicode в utf8 - из рабочей во внешнюю text = text.encode('utf8') # Сохраняем в файл с кодировкий utf8 open('file.txt','w').write(text) 

Текст в скрипте

# coding: utf8 a = 'Текст в utf8' b = u'Текст в unicode' # Эквивалентно: b = 'Текст в unicode'.decode('utf8') # т.к. сам скрипт хранится в utf8 print 'a =',type(a),a # декодируем из utf-8 в unicode и далее unicode в cp866 (кодировка консоли winXP ru) print 'a2 =',type(a),a.decode('utf8').encode('cp866') print 'b =',type(b),b 

Процедуре print текст желательно передавать в рабочей кодировке либо кодировать в кодировку ОС.
Результат скрипта при запуске из консоли windows XP:

a = type 'str'> ╨в╨╡╨║╤Б╤В ╨▓ utf8 a2 = type 'str'> Текст в utf8 b = type 'unicode'> Текст в unicode 

В последней строке print преобразовал unicode в cp866 автоматический, см. следующий пункт

Авто-преобразование кодировки
В некоторых случаях для упрощения разработки python делает преобразование кодировки, пример с методом print можно посмотреть в предыдущем пункте.
В примере ниже, python сам переводит utf8 в unicode — приводит к одной кодировке для того что-бы сложить строки.

# coding: utf8 # Устанавливаем стандартную внешнюю кодировку = utf8 import sys reload(sys) sys.setdefaultencoding('utf8') a = 'Текст в utf8' b = u'Текст в unicode' c = a + b print 'a =',type(a),a print 'b =',type(b),b print 'c =',type(c),c 
a = type 'str'> Текст в utf8 b = type 'unicode'> Текст в unicode c = type 'unicode'> Текст в utf8Текст в unicode 

Как видим результирующая строка «c» в unicode. Если бы кодировки строк совпадали то авто-перекодирования не произошло бы и результирующая строка содержала кодировку слагаемых строк.
Авто-перекодирование обычно срабатывает когда происходит взаимодействие разных кодировок.

Пример авто-преобразования кодировок в сравнении

# coding: utf8 # Устанавливаем стандартную внешнюю кодировку = utf8 import sys reload(sys) sys.setdefaultencoding('utf8') print '1. utf8 and unicode', 'true' if u'Слово'.encode('utf8') == u'Слово' else 'false' print '2. utf8 and cp1251', 'true' if u'Слово'.encode('utf8') == u'Слово'.encode('cp1251') else 'false' print '3. cp1251 and unicode', 'true' if u'Слово'.encode('cp1251') == u'Слово' else 'false' 
1. utf8 and unicode true 2. utf8 and cp1251 false script.py:10: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal print '3. cp1251 and unicode', 'true' if u'Слово'.encode('cp1251') == u'Слово' else 'false' 3. cp1251 and unicode false 

В сравнении 1, кодировка utf8 преобразовалась в unicode и сравнение произошло корректно.
В сравнении 2, сравниваются кодировки одного вида — обе внешние, т.к. кодированы они в разных кодировках условие выдало что они не равны.
В сравнении 3, выпало предупреждение из за того что выполняется сравнение кодировок разного вида — рабочая и внешняя, а авто-декодирование не произошло т.к. стандартная внешняя кодировка = utf8, и декодировать строку в кодировке cp1251 методом utf8 питон не смог.

# coding: utf8 d = ['Тест','списка'] print '1',d print '2',d.__repr__() print '3',','.join(d) 
1 ['\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82', '\xd1\x81\xd0\xbf\xd0\xb8\xd1\x81\xd0\xba\xd0\xb0'] 2 ['\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82', '\xd1\x81\xd0\xbf\xd0\xb8\xd1\x81\xd0\xba\xd0\xb0'] 3 Тест,списка 

При выводе списка, происходит вызов [<repr>]() который возвращает внутреннее представление этого спиcка — print 1 и 2 являются аналогичными. Для корректного вывода списка, его нужно преобразовать в строку — print 3.

Установка внешней кодировки при запуске

PYTHONIOENCODING=utf8 python 1.py 

статья будет дополняться.

Узнать кодировку файла

Есть файл не понятно в какой кодировке, нужно определить кодировку, написал вот такой вариант, но уверен что есть способ определения кодировки на много проще, подскажите.

# какой то файл скачанный с интернета в неизвестной кодировке. open('test.txt', 'w', encoding='cp500').write('Hello\n') # сюда можно впихнуть все известные кодировки. encoding = [ 'utf-8', 'cp500', 'utf-16', 'GBK', 'windows-1251', 'ASCII', 'US-ASCII', 'Big5' ] correct_encoding = '' for enc in encoding: try: open('test.txt', encoding=enc).read() except (UnicodeDecodeError, LookupError): pass else: correct_encoding = enc print('Done!') break print(correct_encoding) 

Отслеживать
задан 1 авг 2017 в 15:17
Игорь Игоряныч Игорь Игоряныч
1,903 4 4 золотых знака 15 15 серебряных знаков 27 27 бронзовых знаков

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

from chardet.universaldetector import UniversalDetector detector = UniversalDetector() with open('test.txt', 'rb') as fh: for line in fh: detector.feed(line) if detector.done: break detector.close() print(detector.result) 

Отслеживать
ответ дан 1 авг 2017 в 16:27
Sergey Gornostaev Sergey Gornostaev
66.5k 6 6 золотых знаков 53 53 серебряных знака 112 112 бронзовых знаков

Еще мудренее чем у меня, и не все кодировки распознает, да еще и левый модуль нужно устанавливать, я так понял проще способа нет.

1 авг 2017 в 17:14

Проще способа нет. Но chardet в этой области признанный стандарт, используемый чуть ли не каждым вторым модулем из PyPI.

1 авг 2017 в 17:17

@ИгорьИгоряныч: способ в вопросе явно неверный: отсутствие исключения не говорит, что «правильную кодировку» нашли — вы таким образом кракозябры можете получить. В общем случае, не существует метода определения «правильной» кодировки. Но отдельные кодировки могут быть более вероятными нежели другие. chardet именно этим и занимается: гадает какие кодировки наибольшие шансы имеют.

Как узнать кодировку файла python

Этот документ (PEP 263 [1]) представляет синтаксис для декларации кодировки текста в файле исходного кода на языке Python. Информация о кодировке затем используется парсером Python для интерпретации файла на указанной кодировке. Прежде всего это улучшает интерпретацию литералов Unicode в исходном коде, и делает возможным писать в литералах Unicode с использованием например UTF-8 напрямую в редакторе, поддерживающем Unicode.

Описываемый ниже метод позволяет избежать ошибок наподобие:

SyntaxError: Non-ASCII character '\xc2' in file имя_модуля.py on line 1261, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

Python source file encoding error

Источник проблемы. В Python 2.1 литералы Unicode могут быть написаны только с использованием кодировки на основе Latin-1 («unicode-escape»). Это делает рабочее окружение программиста не дружественным для пользователей Python, кто живет и работает в странах, где используется не-Latin-1 локаль, как например многие из стран Азии. Программисты могут писать свои тексты своими 8-битными строками в любимой кодировке, но ограничены кодировкой «unicode-escape» для литералов Unicode.

Чаще всего ошибка «SyntaxError: Non-ASCII character» возникает из-за попытки использовать русскоязычные комментарии в файле, кодировка которого не UTF-8. Чтобы быстро исправить проблему, нужно сохранить текст проблемного модуля *.py в кодировке UTF-8, и сообщить об этом интерпретатору Python.

Процесс по шагам:

1. Проверьте, что текст модуля Python сохранен в кодировке UTF-8. В редакторе Notepad2 это делается через меню File -> Encoding. Этот же пункт меню позволяет перекодировать файл в кодировку UTF-8.

2. Добавьте в начало модуля строку:

# -*- coding: utf-8 -*- 

После этого ошибка исчезнет.

Рекомендуемое решение. Рекомендуется сделать кодирование исходного кода Python как видимым, так и изменяемым на уровне исходного файла, применяя в каждом модуле файла исходного кода специальный комментарий в начале файла, чтобы декларировать в нем кодировку.

Чтобы настроить Python для распознавания этой декларации кодировки, необходимо ознакомиться о принципах обработки данных исходного кода Python.

[Определение кодировки]

По умолчанию Python подразумевает, что в файле принят стандарт кодирования ASCII, если не дано никаких других подсказывающих указаний. Чтобы определить кодировку исходного кода, во все исходные файлы нужно добавить «магический» комментарий в первой или второй строке исходного файла:

# coding=

или (используя форматы, распознаваемые популярными редакторами):

#!/usr/bin/python
# -*- coding: < имя_кодировки>-*- 
#!/usr/bin/python
# vim: set fileencoding= < имя_кодировки>: 

Если быть более точным, то первая или вторая строка должна попадать под фильтр следующего регулярного выражения:

^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)

Первая группа этого выражения интерпретируется как имя кодировки. Если эта кодировка не известна для Python, то во время попытки компиляции произойдет ошибка. Не должно быть никакого любого оператора Python в строке, в этой строке, где содержится декларация о кодировке. Если на первую строку регулярное выражение сработает, то вторая строка на предмет поиска кодировки игнорируется.

Чтобы обработать такие платформы, как Windows, которые добавляют маркеры Unicode BOM в начало файла Unicode, UTF-8 сигнатура \xef\xbb\xbf будет также интерпретироваться как кодировка ‘utf-8’ (даже если в файл не добавлен описанный магический комментарий).

Если исходный файл использует одновременно сигнатуру маркера UTF-8 BOM, и магический комментарий, то разрешенной кодировкой для комментария будет только ‘utf-8’. Любая другая кодировка в этом случае приведет к ошибке.

[Примеры]

Ниже приведено несколько примеров, показывающих разные стили определения кодировки исходного кода в начале файла Python.

1. Двоичный интерпретатор и использование файла стиля Emacs:

#!/usr/bin/python
# -*- coding: latin-1 -*-
import os, sys
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
import os, sys
#!/usr/bin/python
# -*- coding: ascii -*-
import os, sys

2. Без строки интерпретатора, используя чистый текст:

# This Python file uses the following encoding: utf-8
import os, sys

3. Текстовые редакторы могут иметь разные способы определения кодировки файла, например:

#!/usr/local/bin/python
# coding: latin-1
import os, sys

4. Без комментария кодировки парсер Python подразумевает, что это текст ASCII:

#!/usr/local/bin/python
import os, sys

[Плохие примеры]

Ниже для полноты приведены ошибочные комментарии для указания кодировки, которые не будут работать.

A. Пропущенный префикс «coding:»:

#!/usr/local/bin/python
# latin-1
import os, sys

B. Комментарий кодировки не находится на строке 1 или 2:

#!/usr/local/bin/python
# -*- coding: latin-1 -*-
import os, sys

C. Не поддерживаемая кодировка:

#!/usr/local/bin/python
# -*- coding: utf-42 -*-
import os, sys

PEP [1] основывается на следующих концепциях, которые должны быть реализованы, чтобы включить использование такого «магического» комментария:

1. Во всем исходном файле Python должна использоваться одинаковая кодировка. Встраивание по-другому закодированных данных приведет к ошибке декодирования на этапе компиляции исходного файла кода Python.

Можно использовать в исходном коде любое кодирование, которое позволяет обработать две первые строки способом, показанным выше, включая ASCII-совместимое кодирование, а также определенные многобайтовые кодировки, такие как Shift_JIS. Это не включает кодировки наподобие UTF-16, которые используют два или большее количество байтов для всех символов. Причина в том, что требуется сохранять простым алгоритм декодирования кодировки в парсере ключевых слов (токенизатор).

2. Обработка escape-последовательностей должна продолжать работать, как она это уже делает, но со всеми возможными кодировками исходного кода, являющимися стандартными строковыми литералами (как 8-битными, так и Unicode). Расширение escape-последовательностей поддерживает только очень малое подмножество возможных вариантов.

3. Комбинация токенизатор/компилятор Python должна быть обновлена, чтобы работать следующим образом:

A. Чтение файла.
B. Декодирование текста файла в Unicode, подразумевая фиксацию кодировки на весь файл. Т. е. файле должна использоваться единая, не изменяемая в пределах файла кодировка (разные файлы могут иметь разные кодировки).
C. Преобразование текста в байтовую строку UTF-8.
D. Разбитие на ключевые слова (токенизация) содержимого UTF-8.
E. Компиляция кода, создание Unicode-объектов из данных Unicode и создание строковых объектов из литеральных данных Unicode. При этом сначала перекодируются данных UTF-8 в 8-битные строковые данные с использованием имеющейся кодировки файла.

Обратите внимание, что идентификаторы Python ограничены подмножеством кодирования ASCII, так что других преобразований не потребуется.

Для обратной совместимости с существующим кодом, который в нестоящее время использует не-ASCII кодировку в строковых литералах без декларации кодирования, реализация будет представлена двумя фразами:

1. Разрешается использование не-ASCII кодировки в строковых литералах и комментариях, при этом внутренне будет рассматриваться отсутствие объявление кодировки как декларация «iso-8859-1». В результате произвольная строка байт будет корректно обработана с предоставлением совместимости с Python 2.2 для литералов Unicode, которые содержат байты, не попадающие в кодировку ASCII.

Будут выдаваться предупреждения по мере появления non-ASCII байтов на входе, один раз на неправильно закодированный входной файл.

2. Удаление предупреждения, и изменение кодировки по умолчанию на «ascii».

Встроенное compile() API будет расширено, чтобы принимать на входе Unicode. 8-битные входные строки являются субъектами стандартной процедуры детектирования кодировки, как это описано выше.

Если строка Unicode с декларацией кодирования будет передана в compile(), будет сгенерировано событие SyntaxError.

[Ссылки]

1. PEP 263 — Defining Python Source Code Encodings site:python.org.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *