8

我花了几个小时来寻找 Unicode 字符串的问题,这些字符串被分解为 Python (2.7) 对我隐藏的东西,但我仍然不明白。首先,我尝试u".."在我的代码中始终如一地使用字符串,但这导致了臭名昭著的UnicodeEncodeError. 我尝试使用.encode('utf8'),但这也无济于事。最后,事实证明我不应该使用任何一个,这一切都会自动进行。然而,我(在这里我需要感谢一位帮助我的朋友)在我的头撞到墙上时确实注意到了一些奇怪的事情。sys.getdefaultencoding()返回ascii,同时sys.stdout.encoding返回UTF-8sys1.在下面的代码中可以正常工作,无需对和 2. 提出任何修改UnicodeEncodeError。如果我更改默认系统编码 reload(sys).setdefaultencoding("utf8"),然后 2. 工作正常。我的问题是为什么这两个编码变量首先是不同的,我如何设法在这段简单的代码中使用错误的编码?请不要将我发送到Unicode HOWTO,我显然在数十个关于UnicodeEncodeError.

#  -*- coding: utf-8 -*-
import sys


class Token:
    def __init__(self, string, final=False):
        self.value = string
        self.final = final

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value

print(sys.getdefaultencoding())
print(sys.stdout.encoding)

# 1.
myString = "I need 20 000€."
tok = Token(myString)
print(tok)

reload(sys).setdefaultencoding("utf8")

# 2.
myString = u"I need 20 000€."
tok = Token(myString)
print(tok)
4

2 回答 2

6

我的问题是为什么这两个编码变量首先是不同的

它们服务于不同的目的。

sys.stdout.encoding应该是您的终端用来解释文本的编码,否则您可能会在输出中得到 mojibake。在一个环境中可能是 utf-8,在另一个环境中可能是 cp437,等等。

sys.getdefaultencoding()在 Python 2 上用于隐式转换(当未显式设置编码时),即 Python 2 可以将仅 ascii 的字节串和 Unicode 字符串混合在一起,例如,xml.etree.ElementTree将 ascii 范围内的文本存储为字节串或json.dumps()返回仅 ascii 的字节串而不是 Unicode在 Python 2 中——可能是由于性能的原因——字节在表示 ascii 字符方面比 Unicode 便宜。Python 3 中禁止隐式转换。

sys.getdefaultencoding()始终'ascii'在 Python 2 中的所有系统上,除非您不应该这样做覆盖它,否则它可能会隐藏错误,并且由于使用可能错误的数据编码的隐式转换,您的数据可能很容易损坏。

顺便说一句,还有另一种常见的编码sys.getfilesystemencoding()可能与两者不同。sys.getfilesystemencoding()应该是用于对 OS 数据(文件名、命令行参数、环境变量)进行编码的编码。

使用声明的源代码编码# -*- coding: utf-8 -*-可能与所有已经提到的编码不同。

自然,如果您从文件、网络中读取数据;它可能使用与上述不同的字符编码,例如,如果在记事本中创建的文件使用 Windows ANSI 编码保存,例如cp1252在另一个系统上,所有标准编码都可能与它不同。

关键是:由于与 Python 无关的原因可能有多种编码,为了避免头痛,使用 Unicode 表示文本:在输入时尽快将编码文本转换为 Unicode,并将其编码为字节(可能使用不同的编码)尽可能晚地输出——这就是所谓的Unicode 三明治的概念。

我如何设法在这段简单的代码中使用错误的编码?

  1. 您的第一个代码示例不好。您在 Python 2 上的字节字符串中使用了不应该使用的非 ascii 文字字符。仅将字节串的文字用于二进制数据(或必要时称为本机字符串)。I need 20 000Γé¼.如果您在任何不使用 utf-8 兼容编码的环境(如 Windows 控制台)中使用 Python 2 运行该代码,则该代码可能会产生诸如(注意字符噪音)之类的 mojibake

  2. 第二个代码示例可以假设reload(sys)不是它的一部分。如果您不想在所有字符串文字前加上u''; 你可以使用from __future__ import unicode_literals

您的实际问题是UnicodeEncodeError错误,reload(sys)不是正确的解决方案!
正确的解决方案是在 POSIX ( LANG, LC_CTYPE)上正确配置您的语言环境,或者如果输出重定向到管道/文件或安装以将 Unicode 打印到 Windows 控制台,则设置PYTHONIOENCODINGwin-unicode-consoleenvvar 。

于 2015-11-16T00:37:46.430 回答
1

我注意到一些标准代码(邮递员库)的相同行为。感谢您的分析,它帮助我节省了一些时间。:-) 问题是完全一样的。我的系统使用sys.getdefaultencoding()和 gets ascii,这不适合处理 1000 个 UTF-8 编码名称的列表。

一方面,stdin/stdout 甚至文件系统编码(utf-8)和另一方面(ascii)的“defaultencoding”之间存在不匹配。此线程:如何在 Python < 3 中将 UTF-8 编码文本打印到控制台?似乎表明它是众所周知的并且正在更改 Python 的默认编码?包含一些迹象表明更同质的(如“utf-8无处不在”)会破坏其他东西,如散列实现。

因此,更改默认编码也不简单。(有关执行此操作的各种方法,请参见http://blog.ianbicking.org/illusive-setdefaultencoding.html。)它已从文件中的sys实例中删除site.py

于 2013-09-14T06:29:34.990 回答