1

我知道类似的问题已经被问过一百万次了,但是尽管阅读了很多问题,我还是找不到适合我情况的解决方案。

我有一个 django 应用程序,我在其中创建了一个管理脚本。该脚本读取一些文本文件,并将它们输出到终端(稍后它将对内容做更多有用的事情,但我仍在对其进行测试)并且字符以转义序列出现,\xc3\xa5而不是预期的å. 由于该转义序列意味着Ã¥,这是å由于编码问题而导致的常见误解,我怀疑至少有两个地方出错了。但是,我不知道在哪里 - 我已经检查了我能想到的所有可能的罪魁祸首:

  • 终端编码为UTF-8;echo $LANGen_US.UTF-8
  • 文本文件以 UTF-8 编码;file *在它们所在的目录中,所有条目都被列为“UTF-8 Unicode 文本”,除了一个不包含任何非 ASCII 字符并被列为“ASCII 文本”的条目。iconv -f ascii -t utf8 thefile.txt > utf8.txt在该文件上运行会产生另一个具有 ASCII 文本编码的文件。
  • Python 脚本都是 UTF-8(或者,在某些情况下,是没有非 ASCII 字符的 ASCII)。我尝试在我的管理脚本中插入带有一些特殊字符的注释,以强制它保存为 UTF-8,但它并没有改变行为。以上对文本文件的观察也适用于所有 Python 脚本文件。
  • 处理文本文件的 Python 脚本# -*- encoding: utf-8 -*-位于顶部;前面的唯一一行是#!/usr/bin/python3,但我尝试过更改.../python为 Python 2.7 或完全删除它以将其留给 Django,但没有结果。
  • 根据文档,“Django 原生支持 Unicode 数据”,因此我“可以在应用程序的任何位置安全地传递 Unicode 字符串”。

我真的想不出其他地方可以在链中寻找非 UTF-8 链接。我在哪里可能错过了更改为 UTF-8 的设置?

为了完整起见:我正在使用标准功能读取文件lines = file.readlines()并打印。print()两端都不会发生手动编码或解码。

更新:

针对评论中的提问:

  • print(sys.getdefaultencoding(), sys.stdout.encoding, f.encoding)产生('ascii', 'UTF-8', None)所有文件。
  • 我开始编译一个 SSCCE,很快发现问题只有在我尝试打印元组中的值时才会出现。换句话说,print(lines[0].strip())工作正常,但print(lines[0].strip(), lines[1].strip())没有。添加.decode('utf-8')会产生一个元组,其中两个字符串都标有前置u\xe5(正确的转义序列å)而不是之前的奇数字符 - 但我不知道如何将它们打印为常规字符串,没有转义字符。我已经测试了另一个调用.decode('utf-8')以及包装,str()但都失败了,因为UnicodeEncodeError抱怨\xe5不能用 ascii 编码。由于单个字符串可以正常工作,我不知道还要测试什么。

SSCCE:

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

import os, sys

for root,dirs,files in os.walk('txt-songs'):
    for filename in files:
        with open(os.path.join(root,filename)) as f:
            print(sys.getdefaultencoding(), sys.stdout.encoding, f.encoding)

            lines = f.readlines()
            print(lines[0].strip()) # works
            print(lines[0].strip(), lines[1].strip()) # does not work
4

3 回答 3

2
于 2013-05-22T18:06:25.780 回答
0

从您的评论看来,您使用的是 python-2 而不是 python-3。

如果您使用的是 python-3,则值得阅读unicode howto guide on reading/writing以了解 python 在做什么。

如果编码的基本流程是:

从编码解码到 unicode -> 处理 -> 从 unicode 编码到编码

在 python3 中,字节被解码为字符串,字符串被编码为字节。字符串解码的字节由open().

[..] 内置的open()函数可以返回一个类似文件的对象,该对象假定文件的内容采用指定的编码并接受诸如 read() 和 write() 等方法的 Unicode 参数。这通过 open() 的编码和错误参数 [..]

因此,要从utf-8 编码文件中读取unicode ,您应该这样做:

# python-3
with open('utf8.txt', mode='r', encoding='utf-8') as f:
    lines = f.readlines() # returns unicode 

如果您想要使用 python-2 的类似功能,您可以使用codecs.open()

# python-2
import codecs
with codecs.open('utf8.txt', mode='r', encoding='utf-8') as f:
    lines = f.readlines() # returns unicode 
于 2013-05-22T04:12:01.520 回答
0

为了完整起见:我正在使用 lines = file.readlines() 读取文件并使用标准 print() 函数进行打印。两端都不会发生手动编码或解码。

在 Python 3.x 中,标准print函数只是将 Unicode 写入sys.stdout. 既然是 a io.TextIOWrapper,它的write方法就等价于:

self.wrapped_binary_file.write(s.encode(self.encoding, self.errors))

因此,一个可能的问题是sys.stdout.encoding与终端的实际编码不匹配。


当然,另一个是您的 shell 编码与终端窗口的编码不匹配。

例如,在 OS X 上,我创建了一个 myscript.py,如下所示:

print('\u00e5')

然后我启动 Terminal.app,创建一个编码为“Western (ISO Latin 1)”的会话配置文件,使用该会话配置文件创建一个选项卡,然后执行以下操作:

$ export LANG=en_US.UTF-8
$ python3 myscript.py

......我得到了你所看到的行为。

于 2013-05-22T00:53:46.527 回答