0

我目前在 Linux (Ubuntu) 下的编码/编码存在严重问题。我以前从来不需要处理这个问题,所以我不知道为什么这实际上不起作用!

我正在从/usr/share/applications/*.desktop解析文件并提取通过 HTTPServer 显示在 Web 浏览器中的信息。我正在使用模板。jinja2

首先,我接到UnicodeDecodeError的电话jinja2.Template.render()中说

utf-8 cannot decode character XXX at position YY [...]

因此,我使来自我的appfind-module(解析*.desktop文件)的所有值都只返回 unicode 字符串。

到目前为止,这个地方的问题已经解决了,但是在某些时候,我正在将一个函数返回的字符串写入BaseHTTPServer.BaseHTTTPRequestHandler.wfile插槽,无论我使用什么编码,我都无法修复这个错误。

此时,写入的字符串wfile来自jinja2.Template.render()afaik,返回一个unicode对象。

奇怪的是,它可以在我的Ubuntu 12.04 LTS上运行,但不能在我朋友的Ubuntu 11.04 LTS上运行。然而,这可能不是原因。他有更多的应用程序,也许他们确实在他们的*.desktop文件中使用了引发错误的编码。

但是,我正确检查了*.desktop文件中的编码:

data = dict(parser.items('Desktop Entry'))

try:
    encoding = data.get('encoding', 'utf-8')
    result = {
        'name':       data['name'].decode(encoding),
        'exec':       DKENTRY_EXECREPL.sub('', data['exec']).decode(encoding),
        'type':       data['type'].decode(encoding),
        'version':    float(data.get('version', 1.0)),
        'encoding':   encoding,
        'comment':    data.get('comment', '').decode(encoding) or None,
        'categories': _filter_bool(data.get('categories', '').
                                        decode(encoding).split(';')),
        'mimetypes':  _filter_bool(data.get('mimetype', '').
                                        decode(encoding).split(';')),
    }

# ...

有人可以告诉我如何解决这个错误吗?我已经阅读了关于我应该unicode()始终使用的 SO 的答案,但是实施起来会非常痛苦,而且我认为它不会在写入时解决问题wfile

谢谢,
尼克拉斯

4

4 回答 4

3

这可能很明显,但无论如何:wfile 是一个普通的字节流:写入的所有内容在写入时都必须是 unicode.encode():ed。

阅读 OP,我不清楚到底发生了什么。但是,有一些技巧可能对您有所帮助,我发现这些技巧有助于调试编码问题。如果这是你早就超越的东西,我提前道歉。

  • cat -v在文件上将所有非 ascii 字符输出为“^X”,这是我发现的唯一一种确定文件真正具有什么编码的万无一失的方法。UTF-8 非 ascii 字符是多字节的。这意味着它们将是多个 '^'-entry by 的序列cat -v

  • 根据我的经验,Shell 环境(LC_ALL 等)是导致问题的最常见原因。确保您的系统具有 UTF-8 和例如 latin-1 可用的语言环境。始终将您的 LC_ALL 设置为明确命名编码的语言环境,例如LC_ALL=sv_SE.iso88591.

  • 在 bash 和 zsh 中,您可以运行对该命令进行特定环境更改的命令,如下所示:

    $ LC_ALL=sv_SE.utf8 python ./foo.py
    

    这使得测试比必须导出不同的语言环境容易得多,而且您不会污染外壳。

  • 不要假设您在内部有 unicode 字符串。编写断言语句来验证字符串是否为 unicode。

    assert isinstance(foo, unicode)
    
  • 学习识别您正在使用的编码中常见字符的损坏/错误表示版本。例如,'\xe4' 是 latin-1 的分音符号,而 'ä' 是组成分音符号的两个 UTF-8 字节,错误地用 latin-1 表示。我发现了解这种 go​​rp 可以大大减少调试编码问题。

于 2012-06-07T19:59:34.123 回答
1

您需要对字节字符串和 Unicode 字符串采取严格的方法。这解释了一切: 实用的 Unicode,或者,我如何停止痛苦?

于 2012-06-08T21:50:30.033 回答
0

默认情况下,当 python 遇到 unicde 的编码问题时,它会引发错误。但是,可以修改此行为,例如错误是预期的还是不重要的。

假设您正在两个作为 ascii 超集的 unicode 页面之间进行转换。两者具有大部分相同的字符,但没有一一对应。因此,您可能希望忽略错误。

为此,请使用errors编码函数中的变量。

mystring = u'This is a test'
print mystring.encode('utf-8', 'ignore')
print mystring.encode('utf-8', 'replace')
print mystring.encode('utf-8', 'xmlcharrefreplace')
print mystring.encode('utf-8', 'backslashreplace')

如果在读/写时使用了错误的编码,则 unicode 会出现很多问题。确保在获得 unicode 字符串后,将其转换为jinja2 所需的 unicode形式。

如果这没有帮助,您能否添加您看到的第二个错误,也许还有一个代码片段来澄清发生了什么?

于 2012-06-07T20:44:20.340 回答
0

尝试在代码段中的所有出现中使用.encode(encoding)而不是。.decode(encoding)

于 2012-06-08T21:19:28.140 回答