【问题标题】:Python encoding - Is there any explanation?Python 编码 - 有什么解释吗?
【发布时间】:2012-03-26 18:11:47
【问题描述】:

有人可以向我解释为什么 python 有这种行为吗?

让我解释一下。

背景

我有一个 python 安装,我想使用一些不在 ASCII 表中的字符。 所以我改变了我的python默认编码。 我以这种方式将每个字符串保存到文件 .py 中 '_MAIL_TITLE_': u'Бронирование номеров',

现在,通过一种替换我的字典键的方法,我想以动态方式将我的字符串插入到 html 模板中。

我放入html页面的标题:

<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 ...... <!-- Some Css's --> 
</head>

不幸的是,我的 html 文档(在替换之后)带有一些错误的字符(未转换?转换错误?)

所以,我打开一个终端并开始下订单:

 1 - Python 2.4.6 (#1, Jan 27 2012, 15:41:03)
 2 - [GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] on linux2
 3 - Type "help", "copyright", "credits" or "license" for more information.
 4 - >>> import sys
 5 - >>> sys.getdefaultencoding()
 6 - 'utf-8'
 7 - >>> u'èéòç'
 8 - u'\xe8\xe9\xf2\xe7'
 9 - >>> u'èéòç'.encode('utf-8')
10 - '\xc3\xa8\xc3\xa9\xc3\xb2\xc3\xa7'
11 - >>> u'è'
12 - u'\xe8'
13 - >>> u'è'.encode()
14 - '\xc3\xa8'

问题

看看第 [7-10] 行。 这不是很奇怪吗?为什么如果我的(第 6 行)python 具有默认编码 utf-8,它会以与第 9 行不同的方式转换该字符串(第 7 行)吗? 现在,看看第 [11-14] 行及其输出。

现在,我完全糊涂了!

提示

所以,我尝试更改终端输入文件的方式(以前是 ISO-8859-1,现在是 utf-8)并且发生了一些变化:

 1 - Python 2.4.6 (#1, Jan 27 2012, 15:41:03)
 2 - [GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] on linux2
 3 - Type "help", "copyright", "credits" or "license" for more information.
 4 - >>> import sys
 5 - >>> sys.getdefaultencoding()
 6 - 'utf-8'
 7 - >>> u'èéòç'
 8 - u'\xc3\xc3\xa8\xc3\xa9\xc3\xb2\xc3\xa7'
 9 - >>> u'èéòç'.encode('utf-8')
10 - '\xc3\xa8\xc3\xa9\xc3\xb2\xc3\xa7'
11 - >>> u'è'
12 - u'\xe8'
13 - >>> u'è'.encode()
14 -'\xc3\xa8'

所以,编码(显式编码)独立于输入编码工作(或者在我看来,但我已经坚持了好几天,所以也许我搞砸了)。

解决方案在哪里??

通过查看backgroundhint 的第8 行,您可以看到创建的unicode 对象存在一些差异。 所以,我已经开始考虑了。 我得出了什么结论?没有。 除了保存我的 .py (包含必须插入到 html 文档中的所有 utf-8 字符)后,我的编码问题可能是 进入 文件的编码

“真实”密码

代码没有什么特别的:它打开一个 html 模板,将它放入一个字符串中,用 unicode(utf-8ed ?希望是)字符串替换占位符,并将其保存到另一个文件中,该文件将从 Internet 可视化(是的,我的“登陆”页面包含标题 utf-8 的规范)。 我这里没有代码,因为它分散在几个文件中,但我确信程序的工作流程(通过跟踪它)。

最后的问题

有鉴于此,有人知道如何让我的代码正常工作吗? 关于unix文件编码的想法?还是 .py 文件编码? 如何更改编码以使我的代码正常工作?

最后提示

在用 utf-8 对象替换占位符之前,如果我插入一个

utf8Obj.encode('latin-1')

我的文档在互联网上完全可见!

感谢回答的人。

EDIT1 - 开发工作流程

好的,这就是我的开发工作流程:

我有该项目的 CVS。该项目位于 centos 操作系统上。该服务器是 64 位机器。 我使用 Eclipse 将我的代码开发成 Windows 7(64 位)。 每次修改都只能通过 CVS 提交来提交。 代码在使用那种 python 的 Centos 机器上执行:

Python 2.4.6 (#1, Jan 27 2012, 15:41:03)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] on linux2

我以这种方式设置了 Eclipse:PREFERENCES -> GENERAL -> WORKSPACE -> TEXT FILE ENCODING : UTF-8

Zope/Plone 应用程序运行在同一台服务器上:它为一些 PHP 页面提供服务。 PHP 页面通过位于 Zope/Plone“服务器”上的 WS 调用一些 python 方法(应用程序逻辑)。该服务器直接连接到应用程序逻辑。

就是这样

EDIT2

这是执行替换的函数:

    def _fillTemplate(self, buf):
    """_fillTemplate(buf)-->str
    Ritorna il documento con i campi sostituiti con dict_template.
    """
    try:    
        for k, v in self.dict_template.iteritems():
            if not isinstance(v,unicode):
                v=str(v)
            else:
                v=v.encode('latin-1') #In that way it works, but why?
            buf = buf.replace(k, v)

【问题讨论】:

  • 像往常一样,首先要检查的是编码链是否在某处损坏。你用什么编辑器?是否设置为将文件保存为 UTF8 或 Latin-1 ?您的 HTML 页面的编码是什么(不是标题,保存了带有女巫的编码)。 python代码文件的编码是什么?你是否将python文件编码头设置为utf8?
  • @e-satis :我使用 eclipse(和 cvs 来提交我的代码),它被设置为在 utf-8 中工作。我的 html 页面也是用 eclipse 编写的。 python代码文件的编码对我来说是一个谜。我怎样才能找回它?最后一个答案也适用于最后一个问题
  • 您是否编写了 Python 代码文件?如果是,您必须知道编码,因为您编写了它。如果你用eclipse写的话,它可能是utf8。如果你没有,那么你不能在不知道编码的情况下使用它。
  • 显然,我编写了自己的代码。但奇怪的是,如果我更改文件的编码(来自 eclipse)并想将其提交回存储库,我的 CVS 对我说从 REP.FILE 到 LOC.FILE 没有任何区别。此外,您如何解释“最后提示”部分?
  • 你的意思是你的机器上没有服务器设置?您不能在本地计算机上解雇 Python 解释器吗?那你在哪里写代码,在windows上?哪个版本?哪种编码?不,这不仅仅是“驱使我去“什么编码有[你的] .py 文件”的信息。它是一个额外的层。所以额外的复杂性。每次添加一个带有编码的层时,都会为错误添加另一个机会。请添加您在 OP 中的所有工作流程。

标签: python character-encoding file-encodings


【解决方案1】:

为了解决这个和未来的问题,我建议您查看问题UnicodeDecodeError when redirecting to file 的答案,其中包含有关此编码/解码业务的一般讨论。


在第一个示例中,您的终端使用 Latin1 编码:

7 - >>> u'èéòç'
8 - u'\xe8\xe9\xf2\xe7'

这些字符在 Latin1 中的编码是对相同字符在 UTF-8 中的有效编码,因此 Python 不需要做任何转换。当您将终端切换到 UTF-8 时,您会得到

7 - >>> u'èéòç'
8 - u'\xc3\xc3\xa8\xc3\xa9\xc3\xb2\xc3\xa7'

您的终端将 UTF-8 编码作为四个 2 字节序列发送到 Python。您的 Python 解释器逐字获取这些字节并保留它们:它们也是您的字符串的有效编码表示; UTF-8 实际上可以以多种 方式对相同 个字符进行编码。


如果您的编辑器保存 UTF-8,那么您应该将以下内容放在 .py 文件的顶部:

# -*- coding: utf-8 -*-

此行必须与您的编辑器使用的编码匹配。


处理编码最稳健的方法可能是以下两种方法之一:

  1. 您的程序应该只在 single 编码中操作内部(字节)字符串(UTF-8 是一个不错的选择)。这意味着如果你得到了,比如说,Latin-1 编码的数据,你应该把它重新编码成 UTF-8:

    data.decode('latin1').encode('utf8')
    

    在这种情况下,处理字符串文字的最佳方法是让编辑器将文件保存为 UTF-8 并使用常规(字节)字符串文字("This is a string",前面没有 u) .

  2. 您的程序也只能处理 Unicode 字符串。我的经验是,使用 Python 2 这有点麻烦。不过,这将是我使用 Python 3 选择的方法,因为 Python 3 对这些编码问题有更自然的支持(文字字符串是字符串,而不是字节字符串等)。

【讨论】:

  • 这是一个有趣的观点。但是,剩下的问题呢?
  • 如果我放那条线,一切都会好起来的。但是,如果我想以这种方式从 WS(xmlrpc 协议)中提取我的字符串,那么一切都会搞砸。如果我不包含该指令,我的 WS 请求将以正确的方式得到满足。所以,对我来说,是一条吃尾巴的狗……
  • 不要 -1 这个。这是答案的一部分。我们无法完整地回答您,因为编码问题伴随着很多变量,其中大部分是 PBCK。
  • 在您的问题中,您说代码没有什么特别之处,只是 HTML。现在你在谈论 xmlrpc。这要复杂得多。您必须将完整的工作流程添加到问题中。另外,设置编码头不是增加问题,而是揭示问题。强迫自己到处添加编码头。如果您的编辑器确实以这种编码保存文件,它应该可以使用它。这样我们就有了工作的基础。
  • @DonCallisto:我建议您阅读并思考我在我链接到的 StackOverflow 问题中的回答;我建议您然后花时间检查程序中编码链的每一步。退后一步,放松一下,仔细考虑程序中处理这些编码问题的每个部分。这并不容易,而且这需要时间,但准确地了解您在每一步中所做的工作将大有帮助。
【解决方案2】:

在第 7 行你输出一个 Unicode 对象:

>>> u'èéòç'
u'\xe8\xe9\xf2\xe7'

不会发生编码,它只是告诉您输入由 Unicode 代码单元 \xe8\xe9 等组成。

在第 11 行,您从 Unicode 对象创建了一个 UTF-8 编码的字符串。编码字符串的输出看起来与未编码的 Unicode 对象不同,但为什么不呢:

>>> u'èéòç'.encode('utf-8')
'\xc3\xa8\xc3\xa9\xc3\xb2\xc3\xa7'

在您更改终端编码的第二个实验中,您实际上破坏了输入字符的解释:

>>> u'èéòç'
u'\xc3\xa8\xc3\xa9\xc3\xb2\xc3\xa7'

当您将这四个字符放入字符串中时,它们会以某种方式被编码,然后 Python 会认为您输入了八个 UTF-8 代码单元字节。但是这些字节并不代表您要输入的字符。看起来 Python 认为它会从终端获取 ISO-8859-1 字符,而实际上它会获取 UTF-8 数据,从而导致一团糟。

【讨论】:

  • 有趣。所以即使在“第 7 行”的情况下?
  • @sth:表示u'\xe8\xe9\xf2\xe7'一般包含代码units,而不是代码points。代码点是与字符相关的数字;代码点与编码的概念无关。代码单元是字符的字节表示,是编码的意义所在。我在您的回答中的几个地方解决了这个问题。参考:en.wikipedia.org/wiki/Code_unit.
【解决方案3】:

当你回答我的评论时,这里是第一个问题的答案:

查看第 [7-10] 行。不是很奇怪吗?为什么如果我的(第 6 行)python 在 utf-8 中有一个默认编码,然后将该字符串(第 7 行)转换为 与第 9 行不同的方式?现在,看一下 [11-14] 行和 他们的输出..

不,这并不奇怪:您必须区分 Python 编码、shell 编码、系统编码、文件编码、声明的文件编码和应用的编码。做了很多编码,不是吗?

sys.getdefaultencoding()

这将为您提供 Python 用于 unicode 实现的编码。这与输出无关。

In [7]: u'è'
Out[7]: u'\xe8'
In [8]: u'è'.encode('utf8')
Out[8]: '\xc3\xa8'
In [9]: print u'è'
è
In [10]: print u'è'.encode('utf8')
è

当您使用print 时,字符会打印到屏幕上,如果您不使用,Python 会为您提供一个表示,您可以复制/粘贴以获得相同的数据。

由于 unicode 字符串与 utf8 字符串不同,它不会为您提供相同的数据。

Unicode 是字符串的“中性”表示,而 utf8 是编码的。

【讨论】:

  • 好的,现在这对我来说已经足够清楚了......但我仍然被我的问题所困扰。
猜你喜欢
  • 2020-08-20
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 2019-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多