Как определить кодировку строки (в string, а не bytes) в Python?
Т.е. нужна либо другая функция для string, либо string нужно превратить в bytes. Подскажите пожалуйста, как это сделать?
Отслеживать
задан 23 окт 2017 в 12:20
Ruslan Sagitov Ruslan Sagitov
11 1 1 золотой знак 1 1 серебряный знак 5 5 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Ошибка указывает, что у вас Питон 3, где str тип, используется для текста — каждая строка (str) это последовательность символов (Unicode codepoints).
Сами символы никакой кодировки не имеют (как внутри интерпретатора строки представлены не имеет значения, до тех пор пока абстракция не нарушена).
Любая кодировка, которая может представить все символы в строке, может быть использована:
>>> "мир".encode('utf-8') b'\xd0\xbc\xd0\xb8\xd1\x80' >>> "мир".encode('cp1251') b'\xec\xe8\xf0' >>> "мир".encode('cp866') b'\xac\xa8\xe0' >>> "мир".encode('koi8-r') b'\xcd\xc9\xd2'
Сама строка никакой кодировки не имеет. Ещё примеры: Как работать с путями c русскими символами?
Вопрос, который можно для строки задать: на каком языке вероятно текст написан? Или более узкий (определённый) вопрос: принадлежат ли все букву заданному диапазону в Unicode.
- Python: How to determine the language?
- How to match Cyrillic characters with a regular expression
Как определить кодировку строки и преобразовать в utf8?
Через imap подключаюсь к серверу и получаю список сообщений. Проблема в кодировке тела письма — в гугле оно одно, в яндексе другое. Хочу чтобы система автоматом определяла кодировку и преобразовывала его в utf8
import cchardet def convert_encoding(data, new_coding = 'UTF-8'): encoding = cchardet.detect(data)['encoding'] if new_coding.upper() != encoding.upper(): data = data.decode(encoding, data).encode(new_coding) return data def get_mails(login, password): print("Connecting to <>. ".format(server)) imap = imaplib.IMAP4_SSL(server) print("Connected! Logging in as <>. ".format(login)); imap.login(login, password) print("Logged in! Listing messages. "); status, select_data = imap.select('INBOX') nmessages = select_data[0].decode('utf-8') status, search_data = imap.search(None, 'ALL') for msg_id in search_data[0].split(): status, msg_data = imap.fetch(msg_id, '(RFC822)') msg_raw = msg_data[0][1].decode("utf8") mail = mailparser.parse_from_string(msg_raw) telo = convert_encoding(mail.body.encode()) # Вот тут траблы
Для примера — mail.body содержит следующий текст
'\\u041f\\u0440\\u043e\\u0432\\u0435\\u0440\\u043a\\u0430 \\u0441'
Выдаёт ошибку
TypeError: decode() argument 2 must be str, not bytes
- Вопрос задан более трёх лет назад
- 1663 просмотра
5 комментариев
Средний 5 комментариев
Как узнать кодировку строки python
На этом шаге мы рассмотрим методы решения указанной задачи .
Документы в Интернете могут быть представлены в различных кодировках. Чтобы документ был правильно обработан, необходимо знать его кодировку. Определить кодировку можно по заголовку Content-Type в заголовках ответа Web -сервера:
Content-Type: text/html; charset=utf-8
Кодировку Web -страницы можно также определить по значению параметра content тега , расположенного в разделе HEAD :
Однако часто встречается ситуация, когда кодировка в ответе сервера не совпадает с кодировкой, указанной в теге , или же таковая вообще не указана. Определить кодировку документа в этом случае позволяет библиотека chardet . Установить ее можно из репозитория PyPI способом, описанным на 228 шаге. Открываем командную строку и набираем в ней команду:
c:\python34\scripts\pip install chardet
Через некоторое время библиотека будет установлена.
Для проверки установки запускаем редактор IDLE и в окне Python Shell выполняем следующий код:
>>> import chardet >>> chardet.__version__ '3.0.4'
Определить кодировку строки позволяет функция detect (< Последовательность байтов >) из модуля chardet . В качестве результата она возвращает словарь с тремя элементами. Ключ encoding содержит название кодировки, ключ language — название языка, а ключ confidence — коэффициент точности определения в виде вещественного числа от 0 до 1. Пример определения кодировки приведен ниже.
>>> import chardet >>> chardet.detect(bytes(«Строка», «cp1251»)) >>> chardet.detect(bytes(«Строка», «utf-8»))
Если файл имеет большой размер, то вместо считывания его целиком в строку и использования функции detect() можно воспользоваться классом UniversalDetector . В этом случае можно читать файл построчно и передавать текущую строку методу feed() . Если определение кодировки прошло успешно, атрибут done будет иметь значение True . Это условие можно использовать для выхода из цикла. После окончания проверки следует вызвать метод close() . Получить результат определения кодировки позволяет атрибут result . Очистить результат и подготовить объект к дальнейшему определению кодировки можно с помощью метода reset() . Пример использования класса UniversalDetector приведен ниже.
from chardet.universaldetector import UniversalDetector ud = UniversalDetector() # Создаем объект for line in open("file.txt", "rb"): ud.feed(line) # Передаем текущую строку if ud.done: break # Прерываем цикл, если done == True ud.close() # Закрываем объект print(ud.result) # Выводим результат
Архив с файлом можно взять здесь.
Результат работы приложения:
Как показали тесты, при использовании кодировки Windows-1251 файл просматривается полностью, и определение кодировки файла, содержащего 6500 строк, занимает почти секунду. Если сменить кодировку файла на UTF-8 без ВОМ , то время определения увеличивается до 5 секунд. Использовать класс UniversalDetector или нет — решать вам.
Замечание . Полное описание библиотеки chardet можно найти по адресу http://chardet.readthedocs.org/en/latest/ .
Со следующего шага мы начнем рассматривать сжатие данных .
Модуль 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)