2014-10-28 6 views
2

Я пытаюсь записать данные в объект StringIO с использованием Python, а затем в конечном итоге загрузить эти данные в базу данных postgres, используя psycopg2's copy_from().UnicodeDecodeError: кодек ascii не может декодировать байт 0x92 в позиции 47: порядковый номер не в диапазоне (128)

Сначала, когда я сделал это, copy_from() выкидывал ошибку: ERROR: неверная последовательность байтов для кодирования «UTF8»: 0xc92 Итак, я следовал this question.

Я понял, что в моей базе данных Postgres есть кодировка UTF8.

Файл/StringIO объект, который я пишу мои данные в показывает свою кодировку, следуя: setgid Non-ISO расширенной ASCII-английский текст, с очень длинными линиями, с CRLF терминаторов линии

Я пытался кодировать каждая строка, которую я пишу в файл промежуточного файла/StringIO в формате UTF8. Для этого используется .encode (encoding = 'UTF-8', errors = 'strict')) для каждой строки.

Это ошибка я получил в настоящее время: UnicodeDecodeError: «ASCII» кодек не может декодировать байт 0x92 в позиции 47: порядковый не в диапазоне (128)

Что это значит? Как это исправить?

EDIT: Я использую Python 2.7 Некоторые части моего кода:

я прочитал из базы данных MySQL, который имеет данные в кодировке UTF-8, как в MySQL Workbench. Это код несколько строк для записи своих данных (который получается из БД MySQL) для объекта StringIO:

# Populate the table_data variable with rows delimited by \n and columns delimited by \t 
row_num=0 
for row in cursor.fetchall() : 

    # Separate rows in a table by new line delimiter 
    if(row_num!=0): 
     table_data.write("\n") 

    col_num=0 
    for cell in row:  
     # Separate cells in a row by tab delimiter 
     if(col_num!=0): 
      table_data.write("\t") 

     table_data.write(cell.encode(encoding='UTF-8',errors='strict')) 
     col_num = col_num+1 

    row_num = row_num+1 

Это код, который записывает в базу данных Postgres из моего StringIO объекта TABLE_DATA:

cursor = db_connection.cursor() 
cursor.copy_from(table_data, <postgres_table_name>) 
+0

Показать свой код –

+0

Какую оболочку MySQL вы используете? – abarnert

+0

Кроме того, вместо того, чтобы показывать «некоторые фрагменты моего кода», создайте автономный [минимальный, полный, проверяемый пример] (http://stackoverflow.com/help/mcve) и опубликуйте его здесь. – abarnert

ответ

6

Проблема в том, что вы вызываете encode на объект str.

A str - это байтовая строка, обычно представляющая текст, закодированный каким-то образом, как UTF-8. Когда вы вызываете encode на это, он сначала должен быть декодирован обратно в текст, поэтому текст может быть перекодирован. По умолчанию Python делает это, вызывая s.decode(sys.getgetdefaultencoding()), а getdefaultencoding() обычно возвращает 'ascii'.

Итак, вы говорите кодированный текст UTF-8, декодируя его, как если бы он был ASCII, а затем перекодировал его в UTF-8.

Общее решение заключается в явном вызове decode с правильной кодировкой, вместо того, чтобы позволить Python использовать значение по умолчанию, а затем encode.

Но когда право кодирования уже один вы хотите, тем проще решение просто пропустить .decode('utf-8').encode('utf-8') и просто использовать UTF-8 str как UTF-8 str, что она уже есть.

Или, в качестве альтернативы, если ваш MySQL обертка имеет функцию, чтобы вы указать кодировку и получить обратно unicode значений CHAR/VARCHAR/TEXT столбцов вместо str значений (например,, в MySQLdb вы передаете use_unicode=True на звонок connect, или charset='UTF-8', если ваша база данных слишком стар, чтобы ее автоматически обнаружить), просто сделайте это. Тогда у вас будет unicode объектов, и вы можете позвонить .encode('utf-8') на них.

В общем, лучший способ справиться с проблемами Юникода - это как можно раньше, все декодировать все, сделать всю обработку в Юникоде, а затем закодировать как можно позже. Но в любом случае, вы должны быть последовательными. Не звоните str на что-то, что может быть unicode; не конкатенировать литерал str на номер unicode или передать его replace; и т. д. Каждый раз, когда вы смешиваете и сопоставляете, Python будет неявно конвертировать для вас, используя стандартную кодировку, которая почти никогда не нужна вам.

В качестве побочного примечания, это одна из многих вещей, с которыми справляется Unicode Python 3.x. Во-первых, str теперь текст Unicode, а не закодированные байты. Что еще более важно, если у вас есть закодированные байты, например, в объекте bytes, вызов encode даст вам AttributeError вместо того, чтобы пытаться бесшумно декодировать, чтобы он мог перекодировать. И, подобно тому, как пытаться смешивать и сопоставлять Unicode и байты, вы получите очевидный TypeError, вместо неявного преобразования, которое преуспевает в некоторых случаях и дает загадочное сообщение о кодировании или декодировании, о котором вы не просили в других.

+0

Я попытался передать в charset = 'UTF-8' в моем соединении с MYSQL DB с use_unicode = True. Также поняли, что некоторые таблицы в исходной базе данных MySQL являются latin1_swedish_ci, а некоторые - utf_8. я получаю сообщение об ошибке, как это сейчас: db_connection = MySQLdb.connect (хост = хост, пользователь = пользователь, PASSWD = PASSWD, дБ = дБ, кодировка = "utf8", use_unicode = True) ячейка = Str (клетки) .replace ("\ r", "") .replace ("\ n", "") .replace ("\ t", '') .replace ("\" "," ") UnicodeEncodeError: 'ascii 'codec не может кодировать символ u' \ u2019 'в позиции 47: порядковый номер не в диапазоне (128) – user3422637

+0

@ user3422637: ОК, если вы хотите использовать объекты 'unicode' вместо' str' - это хорошая идея - то вы не можете называть 'str' на них, потому что это будет немедленно пытаться закодировать их в кодировке по умолчанию. И вы не должны смешивать и сопоставлять объекты' unicode' и 'str', как вы делаете, потому что это также должен неявно кодировать или декодировать тот или иной, использовать 'replace (u" \ r ", u" ")' и тому подобное. (На самом деле '' \ r "' плохо в другой wa y-если у вас есть обратная косая черта, либо выйдите из них, либо используйте строковый литерал.) – abarnert

+0

@ user3422637: В более общем плане, если вы пытаетесь наброситься на вещи, пока они не будут работать, даже не понимая этого, вы просто получите все больше теряется. Если вы не читали [Unicode HOWTO] (https://docs.python.org/2/howto/unicode.html), прочитайте это. – abarnert