UnicodeDecodeError when redirected to the file
我在Ubuntu终端(编码设置为utf-8)中运行此代码两次,一次使用./test.py,另一次使用./test.py >out.txt:uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
没有重定向它会输出一个图形。通过重定向,我得到一个UnicodeDecodeError。有人可以解释为什么我只在第二种情况下得到错误,或者甚至更好地详细解释两种情况下背后发生了什么?
本帖最后由 马猴烧酒 于 2018-9-20 14:53 编辑
“串”有两个截然不同的概念:(1)字符串的字符,(2)数组字节。这种区别在很长一段时间内都被忽略了,不超过256个字符(ASCII,Latin-1,Windows-1252,Mac OS Roman,...):这些编码将一组常见字符映射到0到255之间的数字(即字节),保留在同一操作系统上的文本,就会有多种编码:这样的程序只会简单将文本视为字节(通过操作系统使用的编码)。根据以下两点正确地分离了这两个字符串概念:1. 字符大多与计算机无关:可以在粉笔板等上绘制它们,例如بايثون,中python和蛇图形。机器的“字符”还包括“绘图指令”,例如空格,回车,设置书写方向的指令(用于阿拉伯语等),重音符号等.Unicode标准中包含非常大的字符列表。它涵盖了大多数已知角色。2. 另一方面,计算机确实需要以某种方式表示抽象字符:为此,它们使用字节数组(包括0到255之间的数字),因为它们的内存以字节块的形式出现。将字符转换为字节的必要过程称为编码。因此,计算机需要编码才能表示字符。计算机上存在的任何文本都会被编码(直到显示),无论是发送到终端(需要以特定方式编码的字符),还是保存在文件中。为了显示或正确地“理解”(例如,通过Python解释器),字节流被解码成字符。一些编码(UTF-8,UTF-16,...)由Unicode定义为其字符列表(Unicode因此定义了这些字符的字符列表和编码 - 仍然有人将表达式“Unicode编码”视为UTF-8,但这是不正确的,因为Unicode提供了多种编码)。总之,计算机需要在内部用字节表示字符,它们通过两个操作来完成:编码:字符→字节解码:字节→字符某些编码不能编码所有字符(例如ASCII),而(某些)Unicode编码允许你编码所有Unicode字符。编码也不一定是唯一的,因为一些字符可以直接表示或作为组合表示(例如,基本字符和重音符号)。请注意,换行 的概念增加了一层复杂性,因为它可以由依赖于操作系统的不同(控制)字符表示(这是Python的通用换行文件读取模式的原因)。现在,我所谓的“字符”就是Unicode所谓的“ 用户感知角色 ”。单个字符有时可以通过组合Unicode列表中不同索引处的字符部分(基本字符,重音符号......)来表示,这些字符部分称为“ 代码点 ” - 这些代码点可以组合在一起形成一个“字形集群”。Unicode因此导致字符串的第三个概念,由一系列Unicode代码点组成,位于字节和字符串之间,并且更接近后者。虽然Python可以打印字符串,但Python非字节字符串本质上是Unicode代码点的序列,而不是字符的序列。代码点值是Python \u和\UUnicode字符串语法中使用的值。它们不应与字符的编码混淆(这有一个重要的结果:Python(Unicode)字符串的长度是它的代码点数,它并不总是字符的数量:因此s ="\u1100\u1161\u11a8"; print(s, "len", len(s))(Python 3)각 len 3尽管s是一个韩语字符(因为它用3个代码点表示)。但是,在许多实际情况中,字符串的长度是其字符的数量,因为许多字符通常由Python存储为单个Unicode代码点。在Python 2中,Unicode字符串被称为“Unicode字符串”(unicode类型,文字形式u"…"),而字节数组是“字符串”(str类型,其中字节数组可以例如用字符串文字构造"…")。在Python 3中,Unicode字符串简称为“字符串”(str类型,文字形式"…"),而字节数组则是“字节”(bytes类型,文字形式b"…")。通过这几个关键点,你应该能够理解大多数与编码相关的问题!通常,当你打印 u"…" 到终端时,你不应该得到一个图形:Python知道终端的编码。实际上,你可以检查终端的编码:% pythonPython 2.7.6 (default, Nov 15 2013, 15:20:37) on darwinType "help", "copyright", "credits" or "license" for more information.>>> import sys>>> print sys.stdout.encodingUTF-8如果你的输入字符可以使用终端的编码进行编码,Python将这样做,并将相应的字节发送到你的终端而不会抱怨。然后终端将在解码输入字节后尽力显示字符(最坏的情况是终端字体没有一些字符,而是会打印某种空白)。如果需要,可以通过环境变量设置 stdin,stdout和stderr的编码PYTHONIOENCODING:% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | catUTF-8你的第一个字符(\u001A)是不可打印的。
Python在写入终端,文件,管道等时总是编码Unicode字符串。当写入终端时,Python通常可以确定终端的编码并正确使用它。当写入文件或管道时,Python默认为'ascii'编码。可以告诉Python在通过PYTHONIOENCODING环境变量输出管道时要做什么。shell可以在将Python输出重定向到文件或管道之前设置此变量,因此已知正确的编码。
在你的情况下,你已经打印了4个不常见的字符,你的终端不支持其字体。这里有一个例子来帮助解释行为,我的终端实际支持的字符(使用cp437,而不是UTF-8)。
例1
请注意,#coding注释指示保存源文件的编码。我选择了utf8所以我可以支持我的终端无法支持的源代码。编码重定向到stderr,以便在重定向到文件时可以看到它。
#coding: utf8
import sys
uni = u'αßΓπΣσµτΦΘΩδ∞φ'
print >>sys.stderr,sys.stdout.encoding
print uni
输出(直接从终端运行)
cp437
αßΓπΣσµτΦΘΩδ∞φ
Python正确地确定了终端的编码。
输出(重定向到文件)
None
Traceback (most recent call last):
File "C:\ex.py", line 5, in <module>
print uni
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-13: ordinal not in range(128)
Python无法确定编码(无),因此使用'ascii'默认值。ASCII仅支持转换Unicode的前128个字符。
输出(重定向到文件,PYTHONIOENCODING = cp437)
cp437
我的输出文件是正确的:
C:\>type out.txt
αßΓπΣσµτΦΘΩδ∞φ
解释的这么详细的吗,有心啦
页:
[1]