У меня возникли проблемы с символами юникода в тексте, полученном с разных веб-страниц (на разных сайтах). Я использую BeautifulSoup.
Проблема в том, что ошибка не всегда воспроизводима; иногда она работает с некоторыми страницами, а иногда выдает ошибку UnicodeEncodeError
. Я перепробовал практически все, что только можно придумать, но так и не нашел ничего, что работало бы постоянно без выброса какой-либо ошибки, связанной с Unicode.
Один из участков кода, который вызывает проблемы, показан ниже:
agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
Вот трассировка стека, созданная на НЕКОТОРЫХ строках при выполнении приведенного выше фрагмента:
Traceback (most recent call last):
File "foobar.py", line 792, in <module>
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)
Я подозреваю, что это происходит потому, что некоторые страницы (или, точнее, страницы некоторых сайтов) могут быть закодированы, в то время как другие могут быть некодированными. Все сайты находятся в Великобритании и предоставляют данные, предназначенные для британского потребления - поэтому нет никаких проблем, связанных с интернализацией или работой с текстом, написанным не на английском языке.
Есть ли у кого-нибудь идеи, как это решить, чтобы я мог ПОСТОЯННО устранять эту проблему?
Вам необходимо прочитать Unicode HOWTO по Python. Эта ошибка - самый первый пример.
В общем, перестаньте использовать str
для преобразования из юникода в кодированный текст/байты.
Вместо этого правильно используйте .encode()
для кодирования строки:
p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()
или работайте полностью в юникоде.
Это классическая болевая точка python unicode! Рассмотрим следующее:
a = u'bats\u00E0'
print a
=> batsà
Пока все хорошо, но если мы вызовем str(a), давайте посмотрим, что произойдет:
str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
О, черт, это никому не поможет! Чтобы исправить ошибку, явно закодируйте байты с помощью .encode и укажите python, какой кодек использовать:
a.encode('utf-8')
=> 'bats\xc3\xa0'
print a.encode('utf-8')
=> batsà
Voil\u00E0!
Проблема заключается в том, что когда вы вызываете str(), python использует кодировку символов по умолчанию, чтобы попытаться закодировать переданные вами байты, которые в вашем случае иногда являются представлениями символов юникода. Чтобы решить эту проблему, нужно указать python, как поступить со строкой, которую вы ему передали, используя .encode('whatever_unicode'). В большинстве случаев вы можете использовать utf-8.
Отличное изложение этой темы можно найти в докладе Неда Батчелдера на PyCon здесь: http://nedbatchelder.com/text/unipain.html.
Я нашел элегантно обойти для меня, чтобы удалить символы и продолжают хранить строку как строку в редакции:
yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')
Это's важно заметить, что используя параметр ignore опасно, поскольку он автоматически удаляет любые Unicode(и интернационализации) поддержка от кода, который использует его, как видно здесь (преобразования Юникод):
>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
Тонкая проблема, вызывающая даже печать на неудачу, имеющие ваши переменные окружения установлены неправильно, например. здесь значение lc_all установить, чтобы "с помощью". В Debian они препятствуют его установка: Вики на язык
$ echo $LANG
en_US.utf8
$ echo $LC_ALL
C
$ python -c "print (u'voil\u00e0')"
Traceback (most recent call last):
File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
$ export LC_ALL='en_US.utf8'
$ python -c "print (u'voil\u00e0')"
voilà
$ unset LC_ALL
$ python -c "print (u'voil\u00e0')"
voilà
Я обнаружил, что в большинстве случаев просто убрать эти символы гораздо проще:
s = mystring.decode('ascii', 'ignore')
Проблема в том, что вы'вновь пытается напечатать символ Юникода, но ваш терминал не'т поддерживать его.
Вы можете попробовать установить язык-упак-En пакет`, чтобы исправить это:
sudo apt-get install language-pack-en
который обеспечивает английский перевод обновления данных для всех поддерживаемых пакетов (в том числе Python). Установите другой языковой пакет, при необходимости (в зависимости от того, какие символы вы'вновь пытается напечатать).
На некоторых дистрибутивах Linux это'ы, необходимые для того, чтобы убедиться в том, что английской локали по умолчанию настроены правильно (символы Unicode могут быть обработаны консоли/терминала). Иногда это'ы легче установить, чем настройка вручную.
Затем при написании кода, убедитесь, что вы используете правильную кодировку в коде.
Например:
open(foo, encoding='utf-8')
Если вы'вэ еще есть проблема, дважды проверьте ваши настройки системы, такие как:
/и т. д./По умолчанию/язык
), которые должны напримерЛанг="по язык.В UTF-8"и Значение lc_all="по язык.В UTF-8"и
или:
Значение lc_all=C. В кодировке UTF-8 Ланг=С. в UTF-8
Ланг
/языкового
в оболочке.язык -а | грэп "в кодировке UTF-8"и
Демонстрируя проблемы и решения в свежих виртуальных машин.
Бродяга
):бродяга инит Убунту/trusty64; бродяга вверх; бродяга СШ
<суп>см.: Доступно коробки в Ubuntu.</суп>.
™
): $ питона на C 'принт(у" и\u2122-то");' Обратная трассировка (самый недавний призыв последнего): Файл " в<строка> По себе", 1 линия, в <модуль> UnicodeEncodeError: 'в формате ASCII' кодек может'т кодировать символ U'\u2122' в позиции 0: порядковый номер не в диапазон(128)
$ судо apt-получить -г установка языковых пакетов-Ан Следующие дополнительные пакеты будут установлены: язык-блок-Ан-базы Генерирующая районов... en_GB.В UTF-8... каталог /usr на/sbin/локаль-го поколения: сделано Полное поколение.
$ питона на C 'принт(у" и\u2122-то");' ™
$ Значение lc_all=C. В кодировке UTF-8 в Python -с 'принт(у" и\u2122-то");' ™
Попробуйте эту может решить,
# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
Добавить строку ниже в начале вашего скрипта ( или как вторая линия):
# -*- coding: utf-8 -*-
Что's для определения Python кодирования исходного кода. Подробнее в Пеп 263.
В Shell:
язык -а | грэп "в кодировке UTF-8"и
экспорт значение lc_all=$(локаль -а | grep в кодировке UTF-8)
или вручную, как:
экспорт значение lc_all=C. В кодировке UTF-8
™
:питон -с 'принт(у" и\u2122-то");'
Выше протестирован в Ubuntu.
Здесь'ы перепевах некоторые другие так называемые "КС" и ответы. Есть ситуации, в которых просто выбросить хлопотно символов/строк-это хорошее решение, несмотря на протесты здесь.
def safeStr(obj):
try: return str(obj)
except UnicodeEncodeError:
return obj.encode('ascii', 'ignore').decode('ascii')
except: return ""
Испытания это:
if __name__ == '__main__':
print safeStr( 1 )
print safeStr( "test" )
print u'98\xb0'
print safeStr( u'98\xb0' )
Результаты:
1
test
98°
98
Предложение: вы можете назвать эту функцию для toAscii
вместо этого? Что's дело предпочтений.
Этот был написан для Python 2. Для Python 3, я верю, что вы'll хочу использовать байт(параметр obj,"в формате ASCII и")
, а не ул.(объект)
. Я не't-тест, но я в какой-то момент и пересмотреть ответ.
Простые вспомогательные функции найти здесь.
def safe_unicode(obj, *args):
""" return the unicode representation of obj """
try:
return unicode(obj, *args)
except UnicodeDecodeError:
# obj is byte string
ascii_text = str(obj).encode('string_escape')
return unicode(ascii_text)
def safe_str(obj):
""" return the byte string representation of obj """
try:
return str(obj)
except UnicodeEncodeError:
# obj is unicode
return unicode(obj).encode('unicode_escape')
Просто добавить к переменной кодирования('кодировка UTF-8')
agent_contact.encode('utf-8')
Пожалуйста, откройте терминал и огонь следующую команду:
export LC_ALL="en_US.UTF-8"
Ниже Решение работает для меня, просто добавил
у "в строке"и
(представляющая строку в юникоде) перед моей строкой.
result_html = result.to_html(col_space=1, index=False, justify={'right'})
text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly summary report. Let me know if you have any questions. <br>
<br>
Data Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Data Team</p>
</body></html>
""".format(result_html)
Я просто использовал следующие:
import unicodedata
message = unicodedata.normalize("NFKD", message)
Проверить, что документация говорит об этом:
unicodedata.нормализовать(форма, unistr) вернуть нормальную форму Форма для По строке unistr Юникод. Допустимые значения для формы ‘НФК’, ‘NFKC’, ‘НФД " и " NFKD’.
стандарт Юникод определяет различные формы нормализации Юникода строка, исходя из определения канонической эквивалентности и эквивалентность совместимости. В Юникоде, нескольких персонажей может быть выражается различным образом. Например, символ U+00C7 (лат. буквы C с СЕДИЛЬЮ) могут также быть выражены как последовательность у+0043 (латинская буква С) от U+0327 (объединения СЕДИЛЬ).
для каждого персонажа, существует два нормальных форм: обычной форме C и нормальная форма Д. нормальная форма D (НФД) также известен как канонический разложение, и переводит каждый символ в своей раскладываться. нормальная форма c (ЯТЦ) впервые применяет каноническое разложение, то сочиняет предварительно смешанная героев снова.
В дополнение к этим двум формам, есть два дополнительных нормальных форм на основе эквивалентности совместимости. В кодировке Unicode, определенные знаки поддерживается, который, как правило, будет унифицирована с другими персонажами. Для например, с U+2160 (римская цифра один) на самом деле то же самое как U+0049 (прописная латинская буква i). Однако, он поддерживается в Unicode совместимости с существующими наборами символов (например, набор gb2312).
В нормальной форме КД (NFKD) будет применять декомпозиции совместимости, Т. е. заменить все символы совместимость с их эквиваленты. В В нормальном варианте KC (NFKC) впервые применяет разложение совместимости затем канонический состав.
даже если две строки в юникоде нормализуются и выглядеть так же, к У человека читатель, если сочетание символов, а другой нет, они могут быть не равны.
Решает ее для меня. Простой и легкий.
Мы напоролись на эту ошибку при запуске `manage.py миграция в Джанго с локализованным приспособления.
Наш источник содержит # -*- кодирование: UTF-8 -*-декларацию, MySQL был правильно настроен на utf8 и Убунту имел соответствующего языкового пакета и значения В
/и т. д./По умолчанию/язык`.
Вопрос был просто о том, что контейнер Джанго (мы используем докер) отсутствует "язык" ОКР ВАР.
Установка Ланг
до `язык.В UTF-8 и перезапуск контейнера перед повторным запуском миграции Исправлена проблема.
Увы, это работает в Python 3, по крайней мере...
В Python 3
Иногда ошибка в переменных среды и enconding так
import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
...
print(myText.encode('utf-8', errors='ignore'))
где ошибки игнорируются при кодировании.