Python编码 - 有什么解释吗?

时间:2012-03-09 09:21:09

标签: python character-encoding file-encodings

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

我们来解释一下。

背景

我有一个python安装,我想使用一些不在ASCII表中的字符。 所以我改变了我的python默认enconding。 我以字符'_MAIL_TITLE_': u'Бронирование номеров',

的方式将每个字符串保存到文件.py中

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

我放入html页面的标题:

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

不幸的是,我的html doc来找我(在那些替换之后)有一些错误的字符(未转换?错误转换?)

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

 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有一个defaultencoding utf-8,它是否以与第9行不同的方式转换该字符串(line7)? 现在,看看第[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?wish yes)字符串替换占位符并将其保存到另一个可以从Internet上显示的文件中(是​​的,我的“登陆”页面有标题utf-8的规格)。 我这里没有代码,因为它分散在几个文件中,但我确定程序的工作流程(通过跟踪它)。

最终问题

鉴于此,有没有人想让我的代码工作? 关于unix文件编码的想法?或.py文件编码? 如何更改编码以使我的代码有效?

最后提示

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

utf8Obj.encode('latin-1')

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

感谢那些回答。

EDIT1 - 开发工作流程

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

我有一个该项目的CVS。该项目位于centos OS上。该服务器是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工作:首选 - &gt;一般 - &gt; WORKSPACE - &gt;文本文件编码:UTF-8

Zope / Plone应用程序运行到同一个服务器上:它提供一些PHP页面。 PHP页面通过WS调用一些位于Zope / Plone“服务器”上的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)

3 个答案:

答案 0 :(得分:5)

为了解决这个问题和未来的问题,我建议您查看问题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'

您的终端将四个2字节序列的UTF-8编码发送给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",而不使用{{1}在前面)。

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

答案 1 :(得分:5)

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

  

看看[7-10]行。不奇怪吗?为什么我的(第6行)python   在utf-8中有一个defaultencoding,然后在a中转换该字符串(line7)   第9行的不同方式呢?现在,看看[11-14]和[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时,caracter会打印到屏幕上,否则,Python会为您提供一个可以复制/粘贴以获取相同数据的表示。

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

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

答案 2 :(得分: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数据,导致一团糟。