我对Python2.7中的编码有一些疑问。
1.python代码如下
#s = u"严"
s = u'\u4e25'
print 's is:', s
print 'len of s is:', len(s)
s1 = "a" + s
print 's1 is:', s1
print 'len of s1 is:', len(s1)
输出为:
s is: 严
len of s is: 1
s1 is: a严
len of s1 is: 2
我很困惑,为什么s
的len是1,如何将4e25
存储在1字节中?我还注意到USC-2是2字节长,USC-4是4字节长,为什么unicode字符串s
的长度是1?
2。
(1) 用notepad++(Windows 7)新建一个名为a.py
的文件,并设置该文件的编码ANSI
,在a.py
中的代码如下:
# -*- encoding:utf-8 -*-
import sys
print sys.getdefaultencoding()
s = "严"
print "s:", s
print "type of s:", type(s)
输出为:
ascii
s: 严
type of s: <type 'str'>
(2)使用记事本++(Windows7)新建一个名为b.py
的文件,并设置该文件的编码UTF-8
,在b.py
中的代码如下:
# -*- encoding:gbk -*-
import sys
print sys.getdefaultencoding()
s = "严"
print "s:", s
print "type of s:", type(s)
输出为:
File "D:\pyws\code\\b.py", line 1
SyntaxError: encoding problem: utf-8
(3)将文件b.py
更改如下(文件的编码方式为UTF-8
):
import sys
print sys.getdefaultencoding()
s = "严"
print "s:", s
print "type of s:", type(s)
输出为:
ascii
s: 涓
type of s: <type 'str'>
(4)将文件a.py
更改如下(文件的编码方式为ANSI
):
import sys
print sys.getdefaultencoding()
s = "严"
print "s:", s
print "type of s:", type(s)
输出为:
File "D:\pyws\code\a1.py", line 3
SyntaxError: Non-ASCII character '\xd1' in file D:\pyws\code\a1.py on
line 3, but no encoding declared; see http://www.python.org/peps/pep-0263.html f
or details
为什么问题2中这4个案例的输出不同?有人能详细了解吗?
unicode字符串的全部目的就是这样做。unicode字符串的长度是字符数(即,代码点),而不是字节数。字节数可能因编码而异,但字符数是一个抽象的不变量,不会随编码而改变。
至于第二个问题,答案是在设置文件的编码时,告诉Python如何将该文件中的字节映射到字符。如果指定的编码(使用
# encoding
语法)与文件的实际编码不一致,则会出现不可预测的行为,因为Python试图以一种方式解释字节,但文件的设置使字节实际上意味着其他东西。您得到的行为类型将取决于您使用的编码的具体情况。一些可能性是:
# encoding
指令吗?)而且,在所有情况下,字符串的类型都是
str
,因为您没有将字符串指定为unicode(例如,使用u"..."
)。指定文件编码不会使字符串成为unicode。它只是告诉Python如何解释文件中的字符。然而,这里还有一个更大的问题,那就是:你为什么要用你的例子中的编码来玩那些游戏?没有任何理由使用
# encoding
标记来指定文件实际编码之外的编码,这样做肯定会导致问题。别这么做。您必须知道文件的编码方式,并在# encoding
标记中指定相同的编码方式。对问题1的回答:
在Python版本<;3.3中,Unicode字符串
u''
的长度是使用的UTF-16或UTF-32代码单元数(取决于生成标志),而不是字节数。\u4e25
是一个代码单元,但如果使用UTF-16(Windows上的默认值),则并非所有字符都由一个代码单元表示。在Python3.3中,上述两个函数都将返回1。
Unicode字符也可以由组合代码单元组成,例如
é
。normalize
函数可用于生成组合形式或分解形式:因此,即使在Python3.3中,一个显示字符也可以有一个或多个代码单元,为了得到一致的答案,最好将其规范化为一种或另一种形式。
问题2的答案:
文件顶部声明的编码必须与保存文件的编码一致。声明让Python知道如何解释文件中的字节。
例如,字符
严
在另存为UTF-8的文件中保存为3个字节,但在另存为GBK的文件中保存为2个字节:如果声明了错误的编码,则字节将被错误地解释,Python将显示错误的字符或引发异常。
按评论编辑
2(1)-这取决于系统,因为ANSI是系统区域设置的默认编码。在我的系统中,
cp1252
和记事本++不能显示中文字符。如果我将系统区域设置设置为Chinese(PRC)
,那么我将在控制台终端上获得您的结果。在这种情况下,它正常工作的原因是使用了字节字符串,并且字节只是发送到终端。由于文件是在Chinese(PRC)
区域设置的ANSI
中编码的,因此Chinese(PRC)
区域设置终端会正确解释字节字符串包含的字节。2(2)-文件用UTF-8编码,但编码声明为GBK。当Python读取编码时,它试图将文件解释为GBK,但失败了。您选择了
UTF-8
作为编码,在记事本++中,它还包括一个UTF-8编码字节顺序标记(BOM)作为文件中的第一个字符,而GBK编码解码器没有将其作为有效的GBK编码字符读取,因此在第1行失败。2(3)-文件使用UTF-8编码(带物料清单),但缺少编码声明。Python识别UTF-8编码的BOM并使用UTF-8作为编码,但是文件是GBK格式的。因为使用了字节字符串,所以UTF-8编码的字节被发送到GBK终端,您将得到:
在这种情况下,我很惊讶,因为Python忽略了字节
\xa5
,正如您在下面看到的,当我显式解码错误时,Python抛出一个异常:2(4)-在这种情况下,编码是ANSI(GBK),但没有声明编码,而且在UTF-8中没有类似BOM的BOM来给Python一个提示,因此它采用ASCII,并且不能处理第3行的GBK编码字符。
相关问题 更多 >
编程相关推荐