【问题标题】:Latin-1 and the unicode factory in PythonLatin-1 和 Python 中的 unicode 工厂
【发布时间】:2009-07-20 20:52:20
【问题描述】:

我有一个 Python 2.6 脚本,它对以 Latin-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 调用中。

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

【问题讨论】:

    标签: python unicode


    【解决方案1】:

    在模块开头添加:

    # 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。这会更改脚本源的编码,而不是其数据。
    • @Glenn:我建议这样做是因为我认为 print t 可能会打印 Latin1 原始字符串。
    • 我的脚本没有任何非 ASCII 字符的字符串文字。所以这不应该是一个因素。
    • @Bastien Léonard:我从数据库中获得的数据不是 Unicode。有问题的字符是 0xed。我无法使用 ascii 编解码器解码 0xed。有没有办法只为这个函数更改默认编码,以便unicode 可以工作?
    【解决方案2】:

    也许尝试将 latin1 编码的字符串解码为 un​​icode?​​p>

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

    【讨论】:

    • t.add_row([s.decode('latin-1') if isinstance(s, str) else s for s in rec]) # 我想你的意思是这个(或类似的) .
    • 可能,这取决于漂亮的东西需要什么。
    【解决方案3】:

    快速浏览一下 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> 对数据库执行相同操作。

    【讨论】:

    • 如果它在内部使用 Unicode 对象,应该有一种方法可以取回 Unicode 对象并避免无意义地来回转换它们。只要你总是使用 Unicode 对象,你就可以避免大部分的混乱(这就是 Python 3 的工作方式)。
    • 我相信确实如此:“get_string”。
    • @elo80ka,数据确实存储为 Latin-1。我在编写脚本之前验证了这一点。此外(至少在 Python 2.6 中),不能使用 unicode(int_value, 'latin-1') 强制整数,即使 unicode(int_value) 有效。 @Glenn Maynard,打印结果涉及解码,无论是否明确定义。我必须使用t.get_string().encode('latin-1') 是的,我期待py3k 的广泛采用,以便所有字符串都是Unicode。这样可以省去很多麻烦。
    • @eksortso:你是对的......无论如何,字符集对于数字来说真的没有意义。
    猜你喜欢
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2016-09-15
    • 1970-01-01
    • 2010-09-21
    • 2023-03-15
    相关资源
    最近更新 更多