3

有人可以向我解释为什么 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-8defaultencoding ,它会以与第 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'

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

解决方案在哪里?

通过查看 和 的第 8 行backgroundhint您可以看到创建的 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 方法(应用程序逻辑)。该服务器直接连接到应用程序逻辑。

就这样

编辑2

这是执行替换的函数:

    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)
4

3 回答 3

5

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

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

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

sys.getdefaultencoding()

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

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 是编码的。

于 2012-03-09T09:40:14.743 回答
5

为了解决这个问题和未来的问题,我建议您在重定向到文件时查看问题 UnicodeDecodeError的答案,其中包含有关此编码/解码业务的一般讨论。


在第一个示例中,您的终端使用 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. 您的程序应该只在内部(字节)字符串中操作单一编码(UTF-8 是一个不错的选择)。这意味着,如果您获得了拉丁 1 编码的数据,您应该将其重新编码为 UTF-8:

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

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

  2. 您的程序也可以只操作 Unicode 字符串。我的经验是,这对于 Python 2 来说有点麻烦。不过,这将是我在 Python 3 中选择的方法,因为 Python 3 对这些编码问题有更自然的支持(文字字符串是字符串,而不是字节字符串, ETC。)。

于 2012-03-09T09:26:04.703 回答
3

在第 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 会认为你输入了 8 个 UTF-8 代码单元字节。但是这些字节并不代表您想要输入的字符。看起来 Python 认为它会从终端获取 ISO-8859-1 字符,而实际上它会获取 UTF-8 数据,从而导致一团糟。

于 2012-03-09T10:13:52.790 回答