Latin-1 и фабрика unicode в Python

У меня есть скрипт Python 2.6, который заглатывает специальные символы, закодированные на латинице 1, которые я извлекаю из базы данных SQL Server. Я хотел бы напечатать эти символы, но я немного ограничен, потому что я использую библиотеку, которая вызывает фабрику unicode , и я не знаю, как заставить Python использовать кодек, отличный от ascii .

Сценарий – простой инструмент для возврата данных поиска из базы данных без необходимости выполнять SQL непосредственно в редакторе SQL. Я использую библиотеку PrettyTable 0.5 для отображения результатов.

Ядром сценария является этот бит кода. Кортежи, которые я получаю из курсора, содержат целые и строковые данные, а не данные Unicode. (Я бы использовал adodbapi вместо pyodbc , что бы получить Unicode, но adodbapi дает мне другие проблемы.)

 x = pyodbc.connect(cxnstring) r = x.cursor() r.execute(sql) t = PrettyTable(columns) for rec in r: t.add_row(rec) r.close() x.close() t.set_field_align("ID", 'r') t.set_field_align("Name", 'l') print t 

Но столбец Name может содержать символы, которые выходят за пределы диапазона ASCII. Иногда я получаю сообщение об ошибке, например, в строке 222 prettytable.pyc , когда он добирается до вызова t.add_row :

 UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 12: ordinal not in range(128) 

Это строка 222 в prettytable.py . Он использует unicode , который является источником моих проблем, а не только в этом скрипте, но и в других сценариях Python, которые я написал.

 for i in range(0,len(row)): if len(unicode(row[i])) > self.widths[i]: # This is line 222 self.widths[i] = len(unicode(row[i])) 

Скажите, пожалуйста, что я здесь делаю неправильно. Как я могу сделать работу unicode без взлома prettytable.py или любой из других библиотек, которые я использую? Есть ли способ сделать это?

EDIT: ошибка возникает не в операторе print , а при вызове t.add_row .

EDIT: С помощью Bastien Léonard я придумал следующее решение. Это не панацея, но она работает.

 x = pyodbc.connect(cxnstring) r = x.cursor() r.execute(sql) t = PrettyTable(columns) for rec in r: urec = [s.decode('latin-1') if isinstance(s, str) else s for s in rec] t.add_row(urec) r.close() x.close() t.set_field_align("ID", 'r') t.set_field_align("Name", 'l') print t.get_string().encode('latin-1') 

В конце концов мне пришлось расшифровывать по пути и кодировать на выходе. Все это заставляет меня надеяться, что все порты своих библиотек будут на Python 3.x раньше, чем позже!

  • urllib.quote () бросает KeyError
  • как читать файл, который может быть сохранен как ansi или unicode в python?
  • Как перебирать символы Unicode в Python 3?
  • Литералы Unicode, вызывающие недействительный синтаксис
  • Не-ASCII-символы в Matplotlib
  • UnicodeEncodeError: кодек ascii не может кодировать символы
  • Unicode в PowerShell с Python? Альтернативные оболочки в Windows?
  • Что делает символ «b» перед строковым литералом?
  • 3 Solutions collect form web for “Latin-1 и фабрика unicode в Python”

    Добавьте это в начало модуля:

     # coding: latin1 

    Или декодируйте строку в Unicode самостоятельно.

    [Редактировать]

    Прошло некоторое время с тех пор, как я играл с Unicode, но, надеюсь, этот пример покажет, как конвертировать из Latin1 в Unicode:

     >>> s = u'ééé'.encode('latin1') # a string you may get from the database >>> s.decode('latin1') u'\xe9\xe9\xe9' 

    [Редактировать]

    Документация:
    http://docs.python.org/howto/unicode.html
    http://docs.python.org/library/codecs.html

    Может быть, попробуем декодировать строки с кодировкой latin1 в unicode?

     t.add_row((value.decode('latin1') for value in rec)) 

    После быстрого просмотра источника PrettyTable, кажется, что он работает с объектами юникода внутри (см., _stringify_row , add_row , add_row и add_column ). Поскольку он не знает, что кодирует ваши строки ввода, он использует кодировку по умолчанию, обычно ascii .

    Теперь ascii является подмножеством латинского-1, что означает, что если вы переходите с ascii на latin-1, у вас не должно быть никаких проблем. Однако обратное не верно; не все символы латинского алфавита сопоставляются символам ascii. Чтобы продемонстрировать это:

     >>> s = u'\xed\x31\x32\x33' >>> print s # FAILS: Python calls "s.decode('ascii')", but ascii codec can't decode '\xed' >>> print s.decode('ascii') # FAILS: Same as above >>> print s.decode('latin-1') í123 

    Явно конвертируя строки в unicode (например, вы в конечном итоге сделали), исправляет ситуацию и имеет больше смысла, IMO – вы, скорее всего, знаете, что кодирует ваши данные, чем автор PrettyTable :). BTW, вы можете опустить проверку строк в своем понимании списка, заменив s.decode('latin-1') на unicode(s, 'latin-1') поскольку все объекты могут быть принудительно привязаны к строкам .

    Последнее: не забудьте проверить набор символов вашей базы данных и таблиц – вы не хотите предполагать «latin-1» в коде, когда данные фактически хранятся как что-то еще («utf-8 '?) в базе данных. В MySQL вы можете использовать команду SHOW CREATE TABLE <table_name> чтобы узнать, какой набор символов используется для таблицы, и SHOW CREATE DATABASE <db_name> сделать то же самое для базы данных.

    Python - лучший язык программирования в мире.