Latin-1和Python中的unicode工厂

时间:2009-07-20 20:52:20

标签: python unicode

我有一个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来电。

编辑:在BastienLé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!

3 个答案:

答案 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?

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

答案 2 :(得分:0)

在快速浏览PrettyTable的源代码后,它似乎在内部对unicode对象起作用(例如,请参阅_stringify_rowadd_rowadd_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>对数据库执行相同的操作。