This code should write some text to file.
When I’m trying to write my text to console, everything works. But when I try to write the text into the file, I get UnicodeEncodeError. I know, that this is a common problem which can be solved using proper decode or encode, but I tried it and still getting the same UnicodeEncodeError. What am I doing wrong?
I’ve attached an example.
print "(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)".decode("utf-8")%(dict.get('name'),dict.get('description'),dict.get('ico'),dict.get('city'),dict.get('ulCislo'),dict.get('psc'),dict.get('weby'),dict.get('telefony'),dict.get('mobily'),dict.get('faxy'),dict.get('emaily'),dict.get('dic'),dict.get('ic_dph'),dict.get('kategorie')[0],dict.get('kategorie')[1],dict.get('kategorie')[2])
(StarBuy s.r.o.,Inzertujte s foto, auto-moto, oblečenie, reality, prácu, zvieratá, starožitnosti, dovolenky, nábytok, všetko pre deti, obuv, stroj….
with open("test.txt","wb") as f:
f.write("(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)".decode("utf-8")%(dict.get('name'),dict.get('description'),dict.get('ico'),dict.get('city'),dict.get('ulCislo'),dict.get('psc'),dict.get('weby'),dict.get('telefony'),dict.get('mobily'),dict.get('faxy'),dict.get('emaily'),dict.get('dic'),dict.get('ic_dph'),dict.get('kategorie')[0],dict.get('kategorie')[1],dict.get('kategorie')[2]))
UnicodeEncodeError: ‘ascii’ codec can’t encode character u’u010d’ in position 50: ordinal not in range(128)
Where could be the problem?
9 декабря, 2022 12:22 пп
1 569 views
| Комментариев нет
Development, Python
Unicode (Юникод) — это стандарт кодирования символов для большинства компьютеров. Он гарантирует, что текст — включая буквы, символы, эмодзи и даже управляющие символы — будет выглядеть одинаково на разных устройствах, платформах и в цифровых документах, независимо от операционной системы или программного обеспечения. Это важная составляющая интернета и компьютерной индустрии в целом. Без него всё было бы сложно и хаотично.
Unicode сам по себе не является кодировкой, а больше похож на базу данных почти всех возможных символов. В нём есть кодовая точка (идентификатор для каждого символа в базе данных), которая может иметь значение от 0 до 1,1 миллиона – как видите, скорее всего в ближайшее время эти уникальные кодовые точки не закончатся. Каждая кодовая точка в Unicode обозначается U+n, где U+ — кодовая точка Unicode, а n — это набор для символа из четырех-шести шестнадцатеричных цифр. Unicode намного надежнее ASCII, в котором только 128 символов. Обмен цифровым текстом с помощью ASCII сложнее, так как он основан на американском английском и не поддерживает символы с диакритическими знаками. А в Unicode почти 150 000 символов и он охватывает символы всех языков мира.
Поэтому от языков программирования и требуется правильно обрабатывать текст и обеспечивать интернационализацию программного обеспечения. Python используют для разных целей — от электронной почты до серверов и интернета — у него отличный способ обработки Unicode, он принимает стандарт Unicode для своих строк.
Иногда в работе с Unicode в Python могут возникать трудности и ошибки. В этом мануале представлены основы работы Unicode в Python, которые помогут вам избежать этих проблем. С помощью Python мы интерпретируем Unicode, применим к Unicode функцию нормализации и обработаем ошибки.
Требования
Нам понадобится:
- Python, установленный локально или на удаленном сервере. Если у вас еще не установлен Python, ознакомьтесь с этим мануалом.
- Знание основ программирования и строковых методов Python. Читайте Основы работы со строками в Python 3.
- Знание принципов работы с интерактивной консолью Python. Читайте мануал Использование интерактивной консоли Python.
1: Конвертирование кодовых точек Unicode в Python
Кодирование — это процесс представления данных в читаемой компьютером форме. Существуют разные способы кодирования данных — ASCII, Latin-1 и т. д. У каждой кодировки свои сильные и слабые стороны, но пожалуй, самой распространенной является UTF-8 — тип кодирования, который отображает символы со всего мира в одном наборе. То есть, UTF-8 это незаменимый инструмент для всех, кто работает с интернационализированными данными. В целом, UTF-8 справляется с многими задачами. Он относительно эффективен и может работать в разных программах. UTF-8 конвертирует кодовую точку Unicode в понятные компьютеру шестнадцатеричные байты. Другими словами, Unicode – это маппинг, а UTF-8 позволяет компьютеру понять этот маппинг.
В Python 3 кодировка строк по умолчанию – UTF-8, значит, любая кодовая точка Unicode в строке Python автоматически конвертируется в соответствующий символ.
Сейчас мы создадим символ авторского права (©) с помощью его кодовой точки Unicode в Python. Сначала запустите интерактивную консоль Python в терминале, а затем введите:
>>> s = 'u00A9' >>> s
В этом коде мы создали строку s с кодовой точкой Unicode u00A9. Как упоминалось ранее, поскольку строка Python по умолчанию использует кодировку UTF-8, вывод значения s автоматически заменяет его на соответствующий символ Unicode. Обратите внимание, что u в начале кода обязателен. Без него Python не сможет конвертировать кодовую точку. В выводе получим соответствующий символ Unicode:
'©'
В Python есть встроенные функции для кодирования и декодирования строк. Функция encode() конвертирует строку в байтовую строку.
Для этого откройте интерактивную консоль Python и введите код:
>>> ''.encode('utf-8')
В результате получим байтовую строку символа:
b'xf0x9fx85xa5'
Обратите внимание, что перед каждым байтом стоит x, значит, это шестнадцатеричное число.
Примечание: Ввод спецсимволов Unicode в Windows и Mac отличается. В Windows предыдущий и все последующие примеры этого мануала, где используются символы, вы можете вставить с помощью утилиты Character Map. В Mac нет этой функции, поэтому лучше скопировать символ из примера кода.
Далее с помощью функции decode() конвертируем байтовую строку в обычную. Функция decode() принимает в качестве аргумента тип кодировки. Отметим, что функция decode() может декодировать только байтовую строку, которая задается с помощью буквы b в начале строки. Удаление b приведет к ошибке AttributeError.
В консоли введите:
>>> b'xf0x9fx85xa5'.decode('utf-8')
Получим следующий вывод:
''
Теперь у вас есть базовое понимание интерпретации Unicode в Python. Далее мы разберем встроенный в Python модуль unicodedata, чтобы применить расширенные методы Unicode для строк.
2: Нормализация Unicode в Python
С помощью нормализации можно определить, одинаковы ли два символа, написанные разными шрифтами. Это удобно, когда два символа с разными кодовыми точками дают одинаковый результат. Например, мы воспринимаем символы Unicode R и ℜ как одинаковые, поскольку они оба представляют собой букву R, но для компьютера они разные.
Следующий пример кода это демонстрирует. Откройте консоль Python и введите следующее:
>>> styled_R = 'ℜ' >>> normal_R = 'R' >>> styled_R == normal_R
В результате получим:
False
Вывод будет False, потому что Python не считает эти два символа одинаковыми. Именно поэтому нормализация важна при работе с Unicode.
В Unicode некоторые символы создаются путем объединения нескольких символов в один. Нормализация также важна в этом случае, потому что она обеспечивает согласованность строк. Рассмотрим это на примере. Откройте консоль Python и введите код:
>>> s1 = 'hôtel' >>> s2 = 'hou0302tel' >>> len(s1), len(s2)
В этом коде мы создали строку s1, содержащую символ ô, а строка s2 содержит кодовую точку символа циркумфлекса ( ̂ ). Получим такой вывод:
(5, 6)
Это значит, что две строки состоят из одинаковых символов, но имеют разную длину. Значит, они не подходят под условие равенства. Чтобы это проверить, введите в той же консоли:
>>> s1 == s2
Получим вывод:
False
Хотя строковые переменные s1 и s2 производят один и тот же символ Unicode, они различаются по длине и, следовательно, не равны.
Решить эту проблему можно с помощью функции normalize().
3: Нормализация Unicode с помощью NFD, NFC, NFKD и NFKC
Сейчас мы нормализуем строки Unicode с помощью функции normalize() из библиотеки unicodedata Python в модуле unicodedata (он обеспечивает поиск и нормализацию символов). Функция normalize() может принимать форму нормализации в качестве первого аргумента и нормализуемую строку в качестве второго аргумента. В Unicode существует четыре типа форм нормализации: NFD, NFC, NFKD и NFKC.
NFD разбивает символ на несколько комбинируемых символов. Это делает текст нечувствительным к диакритическим символам, что удобно при поиске и сортировке. Для этого нужно закодировать строку в байты.
Откройте консоль и введите следующее:
>>> from unicodedata import normalize >>> s1 = 'hôtel' >>> s2 = 'hou0302tel' >>> s1_nfd = normalize('NFD', s1) >>> len(s1), len(s1_nfd)
Получим следующий вывод:
(5, 6)
При нормализации строки s1 ее длина увеличилась на один символ. Это происходит по причине того, что символ ô разбивается на два символа — o и ˆ. Следующий код это подтвердит:
>>> s1.encode(), s1_nfd.encode()
В результате, после кодирования нормализованной строки символ o отделился от символа ˆ в строке s1_nfd:
(b'hxc3xb4tel', b'hoxccx82tel')
Форма нормализации NFC раскладывает символ, а затем перекомпонует его с любым доступным объединяющим символом. W3C рекомендует использовать NFC в интернете, поскольку NFC компонует строку для получения максимально короткого результата. Ввод с клавиатуры по умолчанию возвращает составленные строки, поэтому в этом случае рекомендуется применять NFC.
Для примера введите в интерактивную консоль:
>>> from unicodedata import normalize >>> s2_nfc = normalize('NFC', s2) >>> len(s2), len(s2_nfc)
Вывод будет следующим:
(6, 5)
При нормализации строки s2 её длина уменьшилась на единицу. Введите код в интерактивной консоли:
>>> s2.encode(), s2_nfc.encode()
Вывод будет таким:
(b'hoxccx82tel', b'hxc3xb4tel')
Символы o и ˆ соединены в один символ ô.
Формы нормализации NFKD и NFKC применяют для «строгой» нормализации и поиска, сопоставления образцов в строках Unicode. “K” в NFKD и NFKC означает совместимость.
NFD и NFC разделяют символы, но NFKD и NFKC выполняют разделение на совместимость для непохожих эквивалентых символов, при этом удаляются любые различия форматирования. Например, строка ②① не похожа на 21, но обе имеют одно значение. Формы нормализации NFKC и NFKD удаляют форматирование (в данном случае круг вокруг цифр) из символов, чтобы представить их упрощенную форму.
На примере разберем разницу между NFD и NFKD. Откройте интерактивную консоль Python и введите:
>>> s1 = '2⁵ô' >>> from unicodedata import normalize >>> normalize('NFD', s1), normalize('NFKD', s1)
Получаем следующий вывод:
('2⁵ô', '25ô')
Форма NFD не смогла разделить символ экспоненты в строке s1, но NFKD вырезала форматирование экспоненты и заменила символ совместимости (в данном случае экспоненту 5) на его эквивалент (5 в виде цифры). Так как NFD и NFKD разделяют символы, следовательно, ô увеличит длину на единицу. Это подтвердит следующее:
>>> len(normalize('NFD', s1)), len(normalize('NFKD', s1))
Код возвращает:
(4, 4)
Принцип работы NFKC аналогичный, но он скорее не разделяет символы, а компонует их. В консоли Python введите:
>>> normalize('NFC', s1), normalize('NFKC', s1)
Вывод будет следующим:
('2⁵ô', '25ô')
Строка для символа ô уменьшится на единицу, поскольку в NFKC композиционный подход (в случае разделения значение увеличивается на единицу). Проверим это с помощью кода:
>>> len(normalize('NFC', s1)), len(normalize('NFKC', s1))
Получаем вывод:
(3, 3)
Мы разобрали типы нормализации и различия между ними. Далее мы устраним ошибки Unicode в Python.
4: Устранение ошибок Unicode в Python
При работе с Unicode в Python могут возникать два типа ошибок: UnicodeEncodeError и UnicodeDecodeError. Теперь разберем пути их устранения.
Устранение ошибки UnicodeEncodeError
Кодирование в Unicode — это процесс конвертирования строки Unicode в байты с помощью определенной кодировки. Ошибка UnicodeEncodeError возникает при попытке закодировать строку, символы которой не могут быть представлены в заданной кодировке.
Чтобы создать эту ошибку, давайте попробуем закодировать строку с символами, которые не входят в набор ASCII.
Откройте консоль и введите:
>>> ascii_supported = 'u0041' >>> ascii_supported.encode('ascii')
Вывод будет:
b'A'
Затем введите:
>>> ascii_unsupported = 'ufb06' >>> ascii_unsupported.encode('utf-8')
Получим следующий результат:
b'xefxacx86'
Наконец, введите следующее:
>>> ascii_unsupported.encode('ascii')
При запуске этого кода возникнет ошибка:
Traceback (most recent call last): File "<stdin>", line 1, in <module>
UnicodeEncodeError: ‘ascii’ codec can’t encode character ‘ufb06’ in position 0: ordinal not in range(128)
В ASCII ограниченное количество символов, поэтому Python выдает ошибки при нахождении символа, которого нет в кодировке ASCII. Поскольку кодовая система ASCII не распознает кодовую точку ufb06, Python выдаст сообщение об ошибке. В нем идет речь о том, что ASCII имеет диапазон только 128 символов, а соответствующий десятичный эквивалент этой кодовой точки не входит в этот диапазон.
UnicodeEncodeError можно обработать с помощью аргумента errors в функции encode(). У аргумента errors может быть одно из трех значений: ignore, replace и xmlcharrefreplace.
Откройте консоль и введите:
>>> ascii_unsupported = 'ufb06' >>> ascii_unsupported.encode('ascii', errors='ignore')
Получим следующий вывод:
b''
Далее введите:
>>> >>> ascii_unsupported.encode('ascii', errors='replace')
Вывод будет таким:
b'?'
Наконец, введите:
>>> ascii_unsupported.encode('ascii', errors='xmlcharrefreplace')
В результате получим:
b'st'
Во всех случаях Python не выдает ошибку. Значение
ignore пропускает символ, который не может быть закодирован; replace заменяет символ знаком ?; а xmlcharrefreplace заменяет некодируемые символы сущностью XML.
Устранение ошибки UnicodeDecodeError
Ошибка UnicodeEncodeError возникает при попытке декодировать строку, символы которой не могут быть представлены в заданной кодировке.
Чтобы создать эту ошибку, мы попробуем декодировать строку байтов в кодировку, которую невозможно декодировать.
Откройте консоль и введите:
>>> iso_supported = '§' >>> b = iso_supported.encode('iso8859_1') >>> b.decode('utf-8')
Получим следующую ошибку:
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa7 in position 0: invalid start byte
Если вы столкнулись с этой ошибкой, можете применить аргумент errors в функции decode(), c помощью которого можно декодировать строку. Аргумент errors принимает два значения: ignore и replace.
Откройте консоль Python и введите код:
>>> iso_supported = '§A' >>> b = iso_supported.encode('iso8859_1') >>> b.decode('utf-8', errors='replace')
Вывод будет следующим:
'�A'
Затем введите:
>>> b.decode('utf-8', errors='ignore')
Получим такой вывод:
'A'
Значение replace в функции decode() добавляет символ �, а ignore ничего не возвращает, поскольку декодер (в данном случае utf-8) не смог декодировать байты.
При декодировании строки следует помнить, что предполагать ее кодировку нельзя, нужно точно знать, как именно она была закодирована.
Подводим итоги
В этом мануале мы рассмотрели основы работы Unicode в Python. Мы кодировали и декодировали строки, нормализовали данные с помощью NFD, NFC, NFKD и NFKC, а также устранили ошибки Unicode. Также мы применили формы нормализации в сценариях сортировки и поиска. Эти методы помогут устранить ошибки Unicode с помощью Python. Рекомендуем ознакомиться с материалами модуля unicodedata.
Tags: Python, Unicode
debian, python, unicode
0
2
Traceback (most recent call last): File "betfair.py", line 10, in <module> print('u041fu0410u0420u0421u0418u0422u0421u042f ' + baseurl + parturl) UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
Строка такая:
print('ПАРСИТСЯ ' + baseurl + parturl)
Почему так и как исправить?
На убунте 14.04 работает
- Ссылка
Ответ на:
комментарий
от yars068 12.05.16 11:18:17 MSK
Сделал
msg = 'ПАРСИТСЯ ' + baseurl + parturl
msg = msg.encode('utf-8')
print(msg)
Теперь мне выводит в виде кодов юникода, а надо по-русски( Я с мобилки – все не очень удобно делать(
Что я делаю не так и почему на убунте работает?
Qwentor ★★★★★
(12.05.16 12:07:11 MSK)
- Показать ответ
- Ссылка
Ответ на:
комментарий
от Qwentor 12.05.16 12:07:11 MSK
Ответ на:
комментарий
от bvn13 12.05.16 15:33:20 MSK
Ответ на:
комментарий
от Qwentor 12.05.16 15:49:11 MSK
Ну так поставь себе юникодную локаль. sudo dpkg-reconfigure locales
, и там нужные настройки.
- Показать ответ
- Ссылка
Ответ на:
комментарий
от proud_anon 12.05.16 16:05:48 MSK
Недавно наткнулся на такое. Решение — либо костылять свой print через sys.stdout.buffer, либо поправить локаль в переменной окружения на UTF-8. Например LC_ALL='ru_RU.UTF-8',LANG='ru_RU.UTF-8'
.
PolarFox ★★★★★
(12.05.16 16:38:37 MSK)
- Ссылка
Ответ на:
комментарий
от Qwentor 12.05.16 16:33:51 MSK
ru_RU.UTF-8
Не обязательно. Любая юникодная сойдёт. Или любая с русскими символами.
PolarFox ★★★★★
(12.05.16 16:39:31 MSK)
- Ссылка
Ответ на:
комментарий
от Qwentor 12.05.16 16:33:51 MSK
Мне нужно установить ru_RU.UTF-8 по-умолчанию? Установил как вторую – без толку
Любую .UTF-8. Если ты почему-то не хочешь устанавливать UTF-8-локаль по умолчанию, то запускай скрипт как LANG=ru_RU.UTF betfair.py
(или любую другую UTF-8-локаль).
- Показать ответ
- Ссылка
Ответ на:
комментарий
от proud_anon 12.05.16 16:44:50 MSK
Йоу, спасибище! Помогло!
Нажал бы плюсик, если б было)
Qwentor ★★★★★
(12.05.16 17:13:07 MSK)
- Ссылка
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.
Похожие темы
-
Форум
Снова юникод в python (2012) -
Форум
Питон, юникод и конвеер (2015) -
Форум
Python: как принудить к utf-8? (2009) -
Форум
[conky][utf-8][python] Не работает вывод в conky (2010) -
Форум
python && utf-8 (2005)
-
Форум
[python][unicode]jinja (2008) -
Форум
Python, Informix и more (2008) -
Форум
[python3.2][archlinux] (2011) -
Форум
Playonlinux не ищет ничего (2014) -
Форум
lubuntu-software-center crash (2013)
The UnicodeEncodeError normally happens when encoding a unicode string into a certain coding. Since codings map only a limited number of unicode characters to str strings, a non-presented character will cause the coding-specific encode() to fail.
Encoding from unicode to str. >>> u"a".encode("iso-8859-15") 'a' >>> u"u0411".encode("iso-8859-15") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "encodings/iso8859_15.py", line 12, in encode UnicodeEncodeError: 'charmap' codec can't encode character u'u0411' in position 0: character maps to <undefined> >>> u"au0411b".encode("iso-8859-15", "replace") 'a?b' >>> u"au0411b".encode("iso-8859-15", "backslashreplace") 'a\u0411b' >>> u"au0411b".encode("iso-8859-15", "xmlcharrefreplace") 'aБb'
Paradoxically, a UnicodeEncodeError may happen when _decoding_. The cause of it seems to be the coding-specific decode() functions that normally expect a parameter of type str. It appears that on seeing a unicode parameter, the decode() functions “down-convert” it into str, then decode the result assuming it to be of their own coding. It also appears that the “down-conversion” is performed using the ASCII encoder. Hence an encoding failure inside a decoder.
The choice of the ASCII encoder for “down-conversion” might be considered wise because it is an intersection of all codings. The subsequent decoding may only accept a coding-specific str.
However, unlike a similar issue with UnicodeDecodeError while encoding, there would be not ambiguity if decode() simply returned the unicode argument unmodified. There seems to be not such a shortcut in decode() functions as of Python2.5.
Alternatively, a TypeError exception could always be thrown on receiving a unicode argument in decode() functions. (This would require stream.read() to produce only str for StreamReader.read(). The latter would only produce unicode).
Decoding from str to unicode. >>> "a".decode("utf-8") u'a' >>> "xd0x91".decode("utf-8") u'u0411' >>> u"a".decode("utf-8") # Unexpected argument type. u'a' >>> u"u0411".decode("utf-8") # Unexpected argument type. Traceback (most recent call last): File "<stdin>", line 1, in <module> File "encodings/utf_8.py", line 16, in decode UnicodeEncodeError: 'ascii' codec can't encode character u'u0411' in position 0: ordinal not in range(128)
Python 3000 will prohibit decoding of Unicode strings, according to PEP 3137: “encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string”.
CategoryUnicode
so i’m trying to scrap data about motherboard from a local website.
import bs4
import os
import requests
from bs4 import BeautifulSoup as soup
os.chdir('E://')
os.makedirs('E://scrappy', exist_ok=True)
myurl = "https://www.example.com"
res = requests.get(myurl)
page = soup(res.content, 'html.parser')
containers = page.findAll("div", {"class": "content-product"})
filename = 'AM4.csv'
f = open(filename, 'w')
headers = 'Motherboard_Name, Pricen'
f.write(headers)
for container in containers:
Product = container.findAll("div", {"class": "product-title"})
Motherboard_Name = Product[0].text.strip()
Kimat = container.findAll("span", {"class": "price"})
Price = Kimat[0].text
print('Motherboard_Name' + Motherboard_Name)
print('Price' + Price)
f.write(Motherboard_Name + "," + Price.replace(",", "") + "n")
f.close() print("done")
But when i run this code i get an error
UnicodeEncodeError:’charmap’ codec can’t encode character ‘u20b9’ in position 45: character maps to
how can i fix this??
Edit:: So i fixed the unicode error by adding encoding=”utf-8″ ( as it was mentioned here python 3.2 UnicodeEncodeError: ‘charmap’ codec can’t encode character ‘u2013’ in position 9629: character maps to <undefined>) (open(filename, ‘w’,encoding=”utf-8″ ))and it seems to do the work however in the csv file m getting characters like ( ₹ ) before the price.. How can i fix this?