UnicodeEncodeError при присоединении имени файла - PullRequest
8 голосов
/ 05 января 2010

Выдает «UnicodeDecodeError: кодек« ascii »не может декодировать байт 0xc2 в позиции 2: порядковый номер не в диапазоне (128)» при выполнении следующего кода:

filename = 'Spywaj.ttf'
print repr(filename)
>> 'Sp\xc2\x88ywaj.ttf'
filepath = os.path.join('/dirname', filename)

Но файл действителен и существует на диске. Имя файла было извлечено из команды "unzip -l". Как можно объединить имена файлов, как это?

ОС и файловая система

Filesystem: ext3    relatime,errors=remount-ro 0       0
Locale: en_US.UTF-8

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

filename = filename.decode('utf-8')
filepath = os.path.join('/dirname', filename)
print filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'
print os.path.isfile(filepath)
>> False

new_filepath = filepath.encode('Latin-1').encode('utf-8')
print new_filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'
print type(filepath)
>> <type 'unicode'>
print os.path.isfile(new_filepath)
>> False

valid_filepath = glob.glob('/dirname/*.ttf')[0]
print valid_filepath
>> /dirname/Spywaj.ttf (SO cannot display the chars in filename)
print type(valid_filepath)
>> <type 'str'>
print os.path.isfile(valid_filepath)
>> True

Ответы [ 4 ]

8 голосов
/ 05 января 2010

Как в Latin-1 (ISO-8859-1), так и в Windows-1252, 0xc2 было бы заглавной буквой A с акцентом на округлое отражение ... в коде, который вы показываете, нет нигде! Можете ли вы добавить

print repr(filename)

перед вызовом os.path.join (а также поместите '/dirname' в переменную и напечатайте его repr для полноты?). Я думаю, что, может быть, этот случайный персонаж там , но вы по какой-то причине его не видите - repr покажет это.

Если в вашем имени файла есть не-Ascii-символ Latin-1 (или Win-1252), вам нужно использовать Unicode - и / или, в зависимости от вашей ОС и файловой системы, какую-то определенную кодировку.

Редактировать : OP подтверждает, благодаря repr, что на самом деле есть два байта, которые не могут быть ASCII - 0xc2, а затем 0x88, что соответствует ОП думает, что это одна строчная буква L. Хорошо, эта последовательность была бы заглавной буквой A в Юникоде с кареткой (кодовая точка 0x88) в популярной кодировке UTF-8 - как это могло бы выглядеть как строчная буква L для объяснения нищих OP, но я представляю некоторые шрифты могут быть графически достаточно сумасшедшими, чтобы допустить такую ​​путаницу.

Итак, я сначала попробую filename = filename.decode('utf-8') - это должно позволить os.path.join работать. Если open затем блокируется в результирующей строке Unicode (это может работать, в зависимости от файловой системы и ОС), следующая попытка состоит в том, чтобы попробовать использовать .encode('Latin-1') и .encode('utf-8') этого объекта Unicode. Если ни одна из кодировок не работает, информация об используемой ОС и файловой системе, которую OP, я полагаю, еще не предоставила, становится критической.

6 голосов
/ 08 октября 2014

Я исправил UnicodeDecodeError, добавив эти строки в /etc/apache2/envvars и перезапустив Apache.

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

как описано здесь: https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/#if-you-get-a-unicodeencodeerror

Я потратил некоторое время на отладку этого.

2 голосов
/ 05 января 2010
filename = filename.decode('utf-8').encode("latin-1")

у меня работает с файлом из Splywaj.zip

>>> os.path.isfile(filename.decode("utf8").encode("latin-1"))
True
>>>
0 голосов
/ 05 января 2010

Проблема доказательств 1 ###

Выдает «UnicodeDecodeError: кодек« ascii »не может декодировать байт 0xc2 в позиции 2: порядковый номер не в диапазоне (128)» при выполнении следующего кода:

filename = 'Spywaj.ttf'
print repr(filename)
>> 'Sp\xc2\x88ywaj.ttf'
filepath = os.path.join('/dirname', filename)

Я не вижу, как можно получить это исключение - оба аргумента os.path.join являются объектами str. Нет причин пытаться преобразовать что-либо в Unicode. Вы уверены, что приведенный выше код является именно тем, что вы запустили?

Проблема доказательств 2

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

filename = filename.decode('utf-8')
filepath = os.path.join('/dirname', filename)
print filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'

Извините, если предположить, что filename не изменился по сравнению с предыдущим фрагментом, это определенно невозможно. Это выглядит как результат os.path.join('/dirname', repr(filename)) ... пожалуйста, убедитесь, что вы публикуете код, который вы на самом деле выполняли, вместе с фактическим выводом (и с фактической трассировкой, если есть).

Путаница

new_filepath = filepath.encode('Latin-1').encode('utf-8')

Алекс хотел попробовать дважды, каждый раз с одним из этих кодировок - не пытаться один раз с обоими кодировками! Поскольку все символы в filepath были в диапазоне ASCII (см. Доказательную проблему 2), эффект был просто filepath.encode ('ascii')

Простое решение

Вы знаете, как найти имя интересующего вас файла:

valid_filepath = glob.glob('/dirname/*.ttf')[0]

Если вам необходимо жестко закодировать это имя в вашем скрипте, вы можете использовать функцию repr (), чтобы получить представление, которое вы можете ввести в ваш скрипт, не беспокоясь о utf8, unicode, кодировании, декодировании и всем этом шуме:

print repr(valid_filepath)

Предположим, что он печатает '/dirname/Sp\xc2\x88ywaj.ttf' ... тогда все, что вам нужно сделать, это аккуратно скопировать и вставить его в ваш скрипт:

file_path = '/dirname/Sp\xc2\x88ywaj.ttf'
...