关于unicode:python解码/编码地狱(使用jinja2)

python decoding/encoding hell (using jinja2)

我正在使用python中的jinja2模板语言来显示一个网站。

相关的源代码如下:

1
2
3
4
5
6
    # -*- coding: utf-8 -*-
    ...
    template_values = {'name': u'abw?rtz'}
    template = jinja_environment.get_template('Home.html')
    print( template.render(template_values) )
    ...

有趣的是如果我使用:

1
template_values = {'name': u'abw_rtz'}

一切正常!

根据Jinja2 S文件

...For Jinja2 the default encoding of templates is assumed to be
utf-8.

...To explicitly use a Unicode string you have to prefix the string
literal with a u: u'H?nsel und Gretel sagen Hallo'. That way Python
will store the string as Unicode by decoding the string with the
character encoding from the current Python module. If no encoding is
specified this defaults to ‘ASCII’ which means that you can’t use any
non ASCII identifier....

所以,只要用u'?"一切都会好起来的,对吧?

这就是我得到的:

1
2
template_values = {'name': unicode('abw?rtz','utf-8') }
UnicodeDecodeError: 'utf8' codec can't decode byte 0xe4 in position 3: invalid continuation byte
1
2
template_values = {'name': u'abw?rtz' }
SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xe4 in position 0: unexpected end of data
1
2
template_values = {'name': unicode('abw?rtz',"ISO-8859-1") }
--> everything works just perfect!

我正在研究Windows7和sys.getdefaultencoding()返回ASCII。

有人能解释这种奇怪的行为吗?我正在寻找一个解决方案,其中"name":也处理中文或西里尔文字符。


问题很可能出现在用于保存此源文件的文本编辑器中。

源文件是经过编码的字节。您的编辑器必须决定如何存储该?字符。在Windows上,许多文本编辑器将默认为您的OEM代码页,它通常是名为代码页1252的拉丁-1派生,而不是UTF-8。

如果在文件顶部添加一个编码声明,告诉python字节是utf-8,但这些字节不是真正的utf-8,而是cp1252,python会误解它们,导致UnicodeDecodeError如果幸运的话,很难找到mojibake,如果不幸运的话。

如果您已经使用了西里尔文或中文字符,那么问题可能会更明显,因为试图将一个包含中文字符的文件保存为CP1252(它无法处理中文字符),可能会对任何编辑器发出警告或错误。但是将西欧字符保存为CP1252(它可以处理这些字符)可能只是默默地做了错误的事情。(有一些编辑器,尤其是Emacs,可以与python共享它们的编码声明,因此,如果您尝试用该# -*- coding: utf-8 -*-保存文件,它要么保存为utf-8,要么给出非常严厉的警告。但大多数编辑器都不知道您在编码声明中撒谎。)

您如何验证这是问题所在?

最简单的方法是在十六进制编辑器中查看源文件(或者在二进制模式下打开它,并在Python脚本中对其进行十六进制修改,如果您愿意的话)。如果这真的是UTF-8,您应该看到如下内容:

1
61 62 77 c3 a4 72 74 7a    a b w . . r t z

如果是CP1252,你会看到:

1
61 62 77 e4 72 74 7a       a b w ? r t z

区别是两个c3 a4字节(utf-8表示'?')与一个e4(拉丁语-1和cp1252,表示'?').

无论如何,您有两种解决方案:

  • 确保将编辑器配置为默认的UTF-8,并将现有的源文件从CP1252转换为UTF-8。
  • 不要在源代码中使用任何非ASCII字符,而是编写u'abw\u00e4rtz'

这个讨论很有启发性。感谢大家的参与。

以下是我为解决自己的案件所做的:

  • 下载并安装hxd,一个免费的十六进制编辑器。(http://mh-nexus.de/en/downloads.php?产品= HXD)

  • 使用hxd打开相关的"文本"文件。

  • 将charset设置为dos/ibm-ascii。

  • 目视检查"文本"中是否有奇怪的"字符"。

  • 将那些奇怪的"字符"替换为符合您要求的字符。搜索/替换下拉工具非常适合这样做。

  • 完成后保存文件。