UnicodeDecodeError: кодек ascii не может декодировать байт 0xd1 в позиции 2: порядковый номер не в диапазоне (128)

107

Я пытаюсь работать с очень большим набором данных, в котором есть нестандартные символы. Мне нужно использовать юникод в соответствии со спецификациями работы, но я сбит с толку. (И вполне возможно, что все делаю неправильно.)

Я открываю CSV, используя:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

Затем я пытаюсь закодировать его с помощью:

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

Я кодирую все, кроме lat и lng, потому что их нужно отправить в API. Когда я запускаю программу для синтаксического анализа набора данных, чтобы получить то, что я могу использовать, я получаю следующую трассировку.

Traceback (most recent call last):
  File "push_into_db.py", line 80, in <module>
    main()
  File "push_into_db.py", line 74, in main
    district_map = buildDistrictSchoolMap()
  File "push_into_db.py", line 32, in buildDistrictSchoolMap
    county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

Думаю, мне следует сказать вам, что я использую python 2.7.2, и это часть сборки приложения на django 1.4. Я прочитал несколько сообщений по этой теме, но ни один из них, похоже, не применим напрямую. Любая помощь будет оценена.

Вы также можете узнать, что некоторые из нестандартных символов, вызывающих проблему, - это Ñ и, возможно, É.

Джелкимантис
источник
1
Какая у вас исходная кодировка файла? Я думаю, вам следует расшифровать его согласно исходной кодировке, а затем преобразовать в utf 8
сяо 啸
возможный дубликат Encoding дает «кодек ascii не может кодировать символ… порядковый номер не в диапазоне (128)» [Ред .: и, я уверен, еще около миллиона других тоже.]
Карл Кнехтель

Ответы:

152

Юникод не равен UTF-8. Последнее - это просто кодировка для первого.

Вы делаете это неправильно. Вы читаете UTF-8 кодируются данные, так что вы должны декодировать в UTF-8 кодировке строки в строку Юникода.

Так что просто замените .encodeна .decode, и он должен работать (если ваш .csv закодирован в UTF-8).

Но стыдиться нечего. Бьюсь об заклад, 3 из 5 программистов сначала не понимали этого, если не больше;)

Обновление: если ваши входные данные не закодированы в UTF-8, то .decode(), конечно , вам необходимо использовать соответствующую кодировку. Если ничего не указано, python принимает ASCII, что явно не работает с не-ASCII-символами.

ch3ka
источник
1
Причина ошибки в том, что Python пытается автоматически декодировать ее из кодировки по умолчанию, ASCII, чтобы затем можно было закодировать ее, как он указал, в UTF-8. Поскольку данные не являются действительными ASCII, это не работает.
agf 02
7
конечно, но если это данные в кодировке UTF8 (как я предполагаю), то .decode('utf-8')должно сработать , ни?
ch3ka 02
Конечно, вы, наверное, правы. Я просто объяснял, почему вы получаете именно эту ошибку в этой ситуации.
agf 02
1
Отлично! Большое спасибо. Итак, оказалось, что это был .decode ('latin-1') - это имеет смысл, потому что именно Ñ создавал мне проблему. Очередной раз! Спасибо!
jelkimantis
Ваше решение работает в некоторых случаях, но в случае, если я использую это, я получаю еще одну ошибку : кодек ascii не может кодировать символ u '\ xf1' в позиции 2: порядковый номер не в диапазоне (128)
Викаш Мишра
84

Просто добавьте эти строки в свои коды:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Хелили Милиана
источник
5
AttributeError: модуль 'sys' не имеет атрибута 'setdefaultencoding', похоже, не работает в Python 3
skjerns
Woot woot! Это мне помогло.
Сёго Макисима
1
Он работает для моего Python 2.7, обратите внимание, необходима перезагрузка (sys), иначе setdefaultencoding не будет доступен.
Юй Шэнь
1
Это было единственное, что заставило меня работать из многих ТАК вопросов. Спасибо!
Freedo 06
название 'reload' не определено
Давиде
28

для пользователей Python 3. ты можешь сделать

with open(csv_name_here, 'r', encoding="utf-8") as f:
    #some codes

с колбой тоже работает :)

Skrmnghrd
источник
1
Я впервые помог кому-то здесь пройти. чувствует себя хорошо, зная, что я помог :)
Skrmnghrd
1
И вы мне тоже помогли :) Все остальные ответы не работали для чтения файлов. Теперь мне нужно выяснить, как исправить это тоже для записи;)
user2194898
можешь прислать мне ссылку на свой код? Я постараюсь помочь
Skrmnghrd
9

Основная причина ошибки заключается в том, что кодировка по умолчанию, принятая python, - ASCII. Следовательно, если строковые данные, которые должны быть закодированы, encode('utf8')содержат символ, который находится за пределами диапазона ASCII, например, для строки типа 'hgvcj 터 파크 387', python выдаст ошибку, потому что строка не в ожидаемом формате кодирования.

Если вы используете версию python более раннюю, чем версия 3.5, надежным исправлением будет установка кодировки по умолчанию, принятой python, на utf8:

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

Таким образом, python сможет предвидеть символы в строке, выходящие за пределы диапазона ASCII.

Однако, если вы используете python версии 3.5 или выше, функция reload () недоступна, поэтому вам придется исправить ее, используя декодирование, например

name = school_name.decode('utf8').encode('utf8')
Теми Факунле
источник
в чем разница между вашим ответом и моим?
khelili miliana
1
Более подробный. Люди часто считают причинно-следственные связи полезными. И ваш код работает, кстати, без каких-либо отступлений.
Temi Fakunle
1
reload доступен в Python 3, вам просто нужно импортировать его. from imp import reload
Мяу
@Meow, но в Python 3 нет sys.setdefaultencoding. Так что в контексте совместимости py2 \ py3 подойдет некоторая проверка, возможно sys.getdefaultencoding (). Был бы признателен за совет по этому поводу. stackoverflow.com/questions/28127513/…
Konst54
2

Для пользователей Python 3:

изменение кодировки с ascii на latin1 работает.

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

import chardet  
with open("dataset_path", 'rb') as rawdata:  
            result = chardet.detect(rawdata.read(10000))  
print(result)
Притхви
источник
2

На моем компьютере был установлен неправильный языковой стандарт.

Я сначала сделал

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False)- это функция, вызываемая, open()когда вы не предоставляете кодировку . Вывод должен быть 'UTF-8', но в данном случае это какой-то вариант ASCII .

Затем я запустил команду bash localeи получил этот результат

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

Итак, я использовал локаль Ubuntu по умолчанию, которая заставляет Python открывать файлы как ASCII вместо UTF-8. Мне пришлось установить локаль наen_US.UTF-8

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

Если вы не можете изменить всю систему языковых стандартов, вы можете вызвать весь свой код Python следующим образом:

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

или делать

export PYTHONIOENCODING="UTF-8"

чтобы установить его в оболочке, в которой вы его запускаете.

Борис
источник
1

если у вас возникла эта проблема при запуске certbot при создании или обновлении сертификата, используйте следующий метод

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

Эта команда нашла оскорбительный символ «´» в одном из файлов .conf в комментарии. После его удаления (вы можете редактировать комментарии по своему усмотрению) и перезагрузки nginx все снова заработало.

Источник: https://github.com/certbot/certbot/issues/5236

Аниш Варгезе
источник
0

Или, когда вы работаете с текстом в Python, если это текст Unicode, обратите внимание, что это Unicode.

Установите text=u'unicode text'вместо этого просто text='unicode text'.

В моем случае это сработало.

Прости
источник
0

открыть с кодировкой UTF 16 из-за lat и long.

with open(csv_name_here, 'r', encoding="utf-16") as f:
karthik r
источник
0

Он действительно работает, просто беря аргумент 'rb' для чтения двоичного файла вместо чтения 'r'

Хосе Гарсиа-Учеда
источник