我有一个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范围的字符。我有时会在prettytable.pyc
的第222行收到t.add_row
来电时的错误消息:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 12: ordinal not in range(128)
这是prettytable.py
中的第222行。它使用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
工作?有没有办法做到这一点?
编辑:错误不是发生在print
声明,而是t.add_row
来电。
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!
答案 0 :(得分:5)
在模块的开头添加:
# 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
答案 1 :(得分:2)
也许尝试将latin1编码的字符串解码为unicode? p>
t.add_row((value.decode('latin1') for value in rec))
答案 2 :(得分:0)
在快速浏览PrettyTable的源代码后,它似乎在内部对unicode对象起作用(例如,请参阅_stringify_row
,add_row
和add_column
。由于它不知道输入字符串使用的编码,因此它使用默认编码usually ascii。
现在ascii是latin-1的子集,这意味着如果你从ascii转换为latin-1,你应该没有任何问题。然而,相反的情况并非如此;并非所有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的作者更容易知道你的数据正在使用什么字符集。顺便说一句,您可以通过将s.decode('latin-1')
替换为unicode(s, 'latin-1')
来省略列表推导中的字符串检查,因为所有对象都可以强制转换为字符串。
最后一件事:不要忘记检查数据库和表的字符集 - 当数据实际存储为其他内容时,您不希望在代码中假设'latin-1'(' utf-8'?)在数据库中。在MySQL中,您可以使用SHOW CREATE TABLE <table_name>
命令查找表正在使用的字符集,并使用SHOW CREATE DATABASE <db_name>
对数据库执行相同的操作。