使用 print 和 format() 输出的 unicode 字符串不一致

Inconsistent output of unicode strings with print and format()

我从生成 unicode 字符串的数据库查询中读取了一个值。由于此处不相关的原因,数据输入人员将字符串值输入数据库为:"Assessor’s Parcel"(注意 'backward' 撇号)。我正在编写的代码只是通过选定的数据库记录并打印出文本。我使用 .format() 操作将变量中的文本插入到打印输出中。众所周知,.format 在传递 unicode 字符串时失败。因此,为了减少这个难题,我提交了以下示例:

>>> a = u"Assessor’s Parcel"
>>> a
u'Assessor\u2019s Parcel'
>>> print a
Assessor’s Parcel
>>> "{0}".format(a)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 8: ordinal not in range(128)
>>>

以上几行来自 PythonWin 的 'Interactive Window'(PythonWin 2.7.5(默认,2013 年 5 月 15 日,22:43:36)[MSC v.1500 32 位(英特尔)] on win32。 )

为什么 'print a' 产生的输出与 'a' 不同?为什么,如果其中任何一个可以产生合理的输出,.format() 不能?

如果我确定我无法输出 unicode 文本(出于某些未知原因)并且我满足于包含“\u”语法的输出,那么我真的必须包装我的所有内容吗?在执行转换的某些代码(方法或其他方式)中从数据库值输出字符串?

只是 'a' 从 class 的 repr 方法中请求值的 "most raw" 形式。打印通过 str() 转换驱动该值。格式表达式通过另一种不同的转换发送它,一种当前使用 ASCII 的转换。

以下是我的一些正确打印尝试。 print a.encode('utf-8') 似乎是解决方案:

>>> a = u"Assessor’s Parcel"
>>> a
u'Assessor\u2019s Parcel'

>>> print a
Assessor’s Parcel

>>> "{0}".format(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 8: ordinal not in range(128)

>>> a.encode('utf-8')
'Assessor\xe2\x80\x99s Parcel'

>>> print a..encode('utf-8')
  File "<stdin>", line 1
    print a..encode('utf-8')
            ^
SyntaxError: invalid syntax

>>> print a.encode('utf-8')
Assessor’s Parcel

>>> print a.encode('utf-8')
Assessor’s Parcel

>>> print a..encode('utf-8')
  File "<stdin>", line 1

    print a..encode('utf-8')
            ^
SyntaxError: invalid syntax

>>> a.encode('utf-8')
'Assessor\xe2\x80\x99s Parcel'

>>> print a.encode('utf-8')
Assessor’s Parcel

use unicode! (请注意,您的错误是该 HOWTO 的第一个示例)

问题不在于格式,而在于您试图将 unicode 对象放入字节串中,因此它试图对其进行编码(使用默认编码 ascii)。相反,如果您尝试将其格式化为 unicode 文字,则不会有问题..

>>> a = u"Assessor’s Parcel"
>>> '{}'.format(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 8: ordinal not in range(128)
>>> u'{}'.format(a)
u'Assessor\u2019s Parcel'
>>> print u'{}'.format(a)
Assessor’s Parcel
>>>

如果您将字节串放入字节串,这也不是问题。

>>> '{}'.format(a.encode('utf8'))
'Assessor\xe2\x80\x99s Parcel'
>>> print '{}'.format(a.encode('utf8'))
Assessor’s Parcel
>>>

但这使得以后输出到另一种(不同的)编码变得更加困难。

在交互式 shell 中,'a' 会打印 a 的表示。你可以用 print repr(a)

达到同样的效果

print a 将打印 str(a) 到标准输出。 print 将始终对输出进行编码,无论输出的编码是什么。所以 print a 类似于 sys.stdout.write(a.encode(sys.stdout.encoding) + "\n")

请注意u"string""string"的区别。第一个是 Unicode 字符串——一个 Unicode 代码点的序列,而后者是一个二进制字符串——一个字节序列。 Python 3 对两者进行了更严格的区分(我实际上更喜欢 Python 3 因为它更挑剔,因此更能告诉我我做错了什么)

"{0}".format(a)中,"{0}"是二进制字符串。您尝试在该二进制字符串中使用非 ascii 字符格式化 unicode 字符串。失败是因为您需要告诉 Python 如何将 Unicode 字符串转换为二进制字符串。所以你可以这样做:"{0}".format(a.encode('utf-8')).

但是,您可能不需要格式化的二进制字符串,而是格式化的 Unicode 字符串。在这种情况下,您可以这样写:u"{0}".format(a)