Python字符编码详解

Python字符编码详解

http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html

本文简单介绍了各种常用的字符编码的特点,并介绍了在python2.x中如何与编码问题作战 :)      请注意本文关于Python的内容仅适用于2.x,3.x中str和unicode有翻天覆地的变化,请查阅其他相关文档。       尊重作者的劳动,转载请注明作者及原文地址 >.<

1. 字符编码简介

1.1. ASCII

ASCII(American Standard Code for Information Interchange),是一种单字节的编码。计算机世界里一开始只有英文,而单字节可以表示256个不同的字符,可以表示所有的英文字符和许多的控制符号。不过ASCII只用到了其中的一半(\x80以下),这也是MBCS得以实现的基础。

1.2. MBCS

然而计算机世界里很快就有了其他语言,单字节的ASCII已无法满足需求。后来每个语言就制定了一套自己的编码,由于单字节能表示的字符太少,而且同时也需要与ASCII编码保持兼容,所以这些编码纷纷使用了多字节来表示字符,如GBxxx、BIGxxx等等,他们的规则是,如果第一个字节是\x80以下,则仍然表示ASCII字符;而如果是\x80以上,则跟下一个字节一起(共两个字节)表示一个字符,然后跳过下一个字节,继续往下判断。

这里,IBM发明了一个叫Code Page的概念,将这些编码都收入囊中并分配页码,GBK是第936页,也就是CP936。所以,也可以使用CP936表示GBK。

MBCS(Multi-Byte Character Set)是这些编码的统称。目前为止大家都是用了双字节,所以有时候也叫做DBCS(Double-Byte Character Set)。必须明确的是,MBCS并不是某一种特定的编码,Windows里根据你设定的区域不同,MBCS指代不同的编码,而Linux里无法使用MBCS作为编码。在Windows中你看不到MBCS这几个字符,因为微软为了更加洋气,使用了ANSI来吓唬人,记事本的另存为对话框里编码ANSI就是MBCS。同时,在简体中文Windows默认的区域设定里,指代GBK。

1.3. Unicode

后来,有人开始觉得太多编码导致世界变得过于复杂了,让人脑袋疼,于是大家坐在一起拍脑袋想出来一个方法:所有语言的字符都用同一种字符集来表示,这就是Unicode。

最初的Unicode标准UCS-2使用两个字节表示一个字符,所以你常常可以听到Unicode使用两个字节表示一个字符的说法。但过了不久有人觉得256*256太少了,还是不够用,于是出现了UCS-4标准,它使用4个字节表示一个字符,不过我们用的最多的仍然是UCS-2。

UCS(Unicode Character Set)还仅仅是字符对应码位的一张表而已,比如"汉"这个字的码位是6C49。字符具体如何传输和储存则是由UTF(UCS Transformation Format)来负责。

一开始这事很简单,直接使用UCS的码位来保存,这就是UTF-16,比如,"汉"直接使用\x6C\x49保存(UTF-16-BE),或是倒过来使用\x49\x6C保存(UTF-16-LE)。但用着用着美国人觉得自己吃了大亏,以前英文字母只需要一个字节就能保存了,现在大锅饭一吃变成了两个字节,空间消耗大了一倍……于是UTF-8横空出世。

UTF-8是一种很别扭的编码,具体表现在他是变长的,并且兼容ASCII,ASCII字符使用1字节表示。然而这里省了的必定是从别的地方抠出来的,你肯定也听说过UTF-8里中文字符使用3个字节来保存吧?4个字节保存的字符更是在泪奔……(具体UCS-2是怎么变成UTF-8的请自行搜索)

另外值得一提的是BOM(Byte Order Mark)。我们在储存文件时,文件使用的编码并没有保存,打开时则需要我们记住原先保存时使用的编码并使用这个编码打开,这样一来就产生了许多麻烦。(你可能想说记事本打开文件时并没有让选编码?不妨先打开记事本再使用文件 -> 打开看看)而UTF则引入了BOM来表示自身编码,如果一开始读入的几个字节是其中之一,则代表接下来要读取的文字使用的编码是相应的编码:

BOM_UTF8 '\xef\xbb\xbf'      BOM_UTF16_LE '\xff\xfe'       BOM_UTF16_BE '\xfe\xff'

并不是所有的编辑器都会写入BOM,但即使没有BOM,Unicode还是可以读取的,只是像MBCS的编码一样,需要另行指定具体的编码,否则解码将会失败。

你可能听说过UTF-8不需要BOM,这种说法是不对的,只是绝大多数编辑器在没有BOM时都是以UTF-8作为默认编码读取。即使是保存时默认使用ANSI(MBCS)的记事本,在读取文件时也是先使用UTF-8测试编码,如果可以成功解码,则使用UTF-8解码。记事本这个别扭的做法造成了一个BUG:如果你新建文本文件并输入"姹塧"然后使用ANSI(MBCS)保存,再打开就会变成"汉a",你不妨试试 :)

2. Python2.x中的编码问题

2.1. str和unicode

str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str'汉'使用len()函数时,结果是3,因为实际上,UTF-8编码的'汉' == '\xE6\xB1\x89'。

unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'汉') == 1。

再来看看encode()和decode()两个basestring的实例方法,理解了str和unicode的区别后,这两个方法就不会再混淆了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
# coding: UTF-8
u = u'汉'
print repr(u) # u'\u6c49'
s = u.encode('UTF-8')
print repr(s) # '\xe6\xb1\x89'
u2 = s.decode('UTF-8')
print repr(u2) # u'\u6c49'
# 对unicode进行解码是错误的
# s2 = u.decode('UTF-8')
# 同样,对str进行编码也是错误的
# u2 = s.encode('UTF-8')

需要注意的是,虽然对str调用encode()方法是错误的,但实际上Python不会抛出异常,而是返回另外一个相同内容但不同id的str;对unicode调用decode()方法也是这样。很不理解为什么不把encode()和decode()分别放在unicode和str中而是都放在basestring中,但既然已经这样了,我们就小心避免犯错吧。

2.2. 字符编码声明

源代码文件中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下:

?
1
#-*- coding: UTF-8 -*-

实际上Python只检查#、coding和编码字符串,其他的字符都是为了美观加上的。另外,Python中可用的字符编码有很多,并且还有许多别名,还不区分大小写,比如UTF-8可以写成u8。参见http://docs.python.org/library/codecs.html#standard-encodings。

另外需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心 :)

2.3. 读写文件

内置的open()方法打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()。write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成unicode后再使用写入的编码进行encode()。如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# coding: UTF-8
f = open('test.txt')
s = f.read()
f.close()
print type(s) # <type 'str'>
# 已知是GBK编码,解码成unicode
u = s.decode('GBK')
f = open('test.txt', 'w')
# 编码成UTF-8编码的str
s = u.encode('UTF-8')
f.write(s)
f.close()

另外,模块codecs提供了一个open()方法,可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# coding: GBK
import codecs
f = codecs.open('test.txt', encoding='UTF-8')
u = f.read()
f.close()
print type(u) # <type 'unicode'>
f = codecs.open('test.txt', 'a', encoding='UTF-8')
# 写入unicode
f.write(u)
# 写入str,自动进行解码编码操作
# GBK编码的str
s = '汉'
print repr(s) # '\xba\xba'
# 这里会先将GBK编码的str解码为unicode再编码为UTF-8写入
f.write(s)
f.close()

2.4. 与编码相关的方法

sys/locale模块中提供了一些获取当前环境下的默认编码的方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# coding:gbk
import sys
import locale
def p(f):
    print '%s.%s(): %s' % (f.__module__, f.__name__, f())
# 返回当前系统所使用的默认字符编码
p(sys.getdefaultencoding)
# 返回用于转换Unicode文件名至系统文件名所使用的编码
p(sys.getfilesystemencoding)
# 获取默认的区域设置并返回元祖(语言, 编码)
p(locale.getdefaultlocale)
# 返回用户设定的文本数据编码
# 文档提到this function only returns a guess
p(locale.getpreferredencoding)
# \xba\xba是'汉'的GBK编码
# mbcs是不推荐使用的编码,这里仅作测试表明为什么不应该用
print r"'\xba\xba'.decode('mbcs'):", repr('\xba\xba'.decode('mbcs'))
#在笔者的Windows上的结果(区域设置为中文(简体, 中国))
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): ('zh_CN', 'cp936')
#locale.getpreferredencoding(): cp936
#'\xba\xba'.decode('mbcs'): u'\u6c49'

3.一些建议

3.1. 使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明。

这点是一定要做到的。

3.2. 抛弃str,全部使用unicode。

按引号前先按一下u最初做起来确实很不习惯而且经常会忘记再跑回去补,但如果这么做可以减少90%的编码问题。如果编码困扰不严重,可以不参考此条。

3.3. 使用codecs.open()替代内置的open()。

如果编码困扰不严重,可以不参考此条。

3.4. 绝对需要避免使用的字符编码:MBCS/DBCS和UTF-16。

这里说的MBCS不是指GBK什么的都不能用,而是不要使用Python里名为'MBCS'的编码,除非程序完全不移植。

Python中编码'MBCS'与'DBCS'是同义词,指当前Windows环境中MBCS指代的编码。Linux的Python实现中没有这种编码,所以一旦移植到Linux一定会出现异常!另外,只要设定的Windows系统区域不同,MBCS指代的编码也是不一样的。分别设定不同的区域运行2.4小节中的代码的结果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#中文(简体, 中国)
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): ('zh_CN', 'cp936')
#locale.getpreferredencoding(): cp936
#'\xba\xba'.decode('mbcs'): u'\u6c49'
#英语(美国)
#sys.getdefaultencoding(): UTF-8
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): ('zh_CN', 'cp1252')
#locale.getpreferredencoding(): cp1252
#'\xba\xba'.decode('mbcs'): u'\xba\xba'
#德语(德国)
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): ('zh_CN', 'cp1252')
#locale.getpreferredencoding(): cp1252
#'\xba\xba'.decode('mbcs'): u'\xba\xba'
#日语(日本)
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): ('zh_CN', 'cp932')
#locale.getpreferredencoding(): cp932
#'\xba\xba'.decode('mbcs'): u'\uff7a\uff7a'

可见,更改区域后,使用mbcs解码得到了不正确的结果,所以,当我们需要使用'GBK'时,应该直接写'GBK',不要写成'MBCS'。

UTF-16同理,虽然绝大多数操作系统中'UTF-16'是'UTF-16-LE'的同义词,但直接写'UTF-16-LE'只是多写3个字符而已,而万一某个操作系统中'UTF-16'变成了'UTF-16-BE'的同义词,就会有错误的结果。实际上,UTF-16用的相当少,但用到的时候还是需要注意。

转载于:https://www.cnblogs.com/kungfupanda/p/4318743.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279292.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用sql服务器发送贺卡_创建和发送免费电子贺卡的最佳网站

使用sql服务器发送贺卡With the holiday season upon us, it’s time to pull out the holiday card list and get writing. However, how would you like to save some money this year and also help save the environment? 随着假期的到来&#xff0c;是时候抽出节日贺卡清…

职称申报评审管理系统_《四川省职称评审管理暂行办法》出台

我省将探索实行职称评审电子证书&#xff0c;电子证书与纸质证书具有同等效力。12月29日&#xff0c;记者从省人社厅了解到&#xff0c;我省近日出台《四川省职称评审管理暂行办法》&#xff0c;从职称评审总体要求、评审主体、申报程序、组织实施、优化服务、强化监管等方面提…

WordCount--统计输入文件的字符数、行数、单词数(java)--初级功能

码云地址&#xff1a; https://gitee.com/YuRenDaZ/WordCount 个人PSP表格&#xff1a; PSP2.1 PSP阶段 预估耗时 &#xff08;分钟&#xff09; 实际耗时 &#xff08;分钟&#xff09; Planning 计划 180 120 Estimate 估计这个任务需要多少时间 180 120 D…

网页的验证码

1.首先可以写一个产生随机验证码的aspx文件&#xff0c;如下产生四位数字&#xff1a; private void Page_Load(object sender, System.EventArgs e) { this.CreateCheckCodeImage(GenerateCheckCode()); } private string GenerateCheckCode() { …

荣耀9igoogle模式_iGoogle个性化主页的6种替代方法

荣耀9igoogle模式iGoogle has less than a year to go before it’s shut down for good on November 1, 2013. While Google seems to think that iGoogle isn’t necessary anymore, there are other services waiting to take its place. iGoogle距离其2013年11月1日永久关闭…

华为堡垒机_安恒信息成为“华为云优秀严选合作伙伴”,携手保障“云上”资产安全访问...

加快5G持续创新能力&#xff0c;为云计算行业注入新动能。近日&#xff0c;以“智者•同行•共赢”为主题的2020华为云ISV(严选)合作伙伴大会在杭州隆重举行。上百位华为云合作伙伴、行业大咖等专业人士齐聚一堂&#xff0c;探讨云计算产业热门话题。作为华为云重要的生态合作伙…

zip4j实现多线程压缩

使用的jar包&#xff1a;zip4j_1.3.2.jar 基本功能&#xff1a; 针对ZIP压缩文件创建、添加、分卷、更新和移除文件 (读写有密码保护的Zip文件) (支持AES 128/256算法加密) (支持标准Zip算法加密) (支持zip64格式) (支持Store(仅打包&#xff0c;默认不压缩&#xff0c;…

非三星手机无法登录三星账号_如何解决所有三星手机的烦恼

非三星手机无法登录三星账号Samsung is the biggest manufacturer of Android phones in the world, but that doesn’t mean these handsets are perfect out of the box. In fact, most of these phones have several annoyances initially—here’s how to fix many of thes…

设置单元格填充方式_单元格的选择及设置单元格格式

数据输入完毕&#xff0c;接下来可以设置字体、对齐方式、添加边框和底纹等方式设置单元格格式&#xff0c;从而美化工作表。要对单元格进行设置&#xff0c;首先要选中单元格。选择单元格选择单元格是指在工作表中确定活动单元格以便在单元格中进行输入、修改、设置和删除等操…

Recover Binary Search Tree

Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing its structure. Note: A solution using O(n) space is pretty straight forward. Could you devise a constant space solution? 要求找到BST中放错位置的两个节点. …

springboot三种过滤功能的使用与比较

若要实现对请求的过滤&#xff0c;有三种方式可供选择&#xff1a;filter、interceptort和aop。本文主要讨论三种拦截器的使用场景与使用方式。 下文中的举例功能是计算每个请求的从开始到结束的时间&#xff0c;例子来源是慕课网。 一、filter 特点&#xff1a;可以获取原始的…

后缀的形容词_构词法(18)构成形容词的常见后缀 3

即时练习一、按要求改写下列单词。1. Japan →___________ adj. 日本(人)的2. Canton →_________ adj. 广东(人)的3. Vietnam →__________ adj. 越南(人)的4. Europe →__________ adj. 欧洲(人)的5. India → ________ adj. 印度(人)的6. Africa →_______ adj. 非洲(人)的7…

CentOS 桌面启动无登录界面

最近VMWare下搞了2个CentOS 32bit虚拟机, 装了些软件之后&#xff0c;都遇到开机无法显示登录界面&#xff0c; 仅能看见桌面背景图的情况。 以下是我搜索很久汇总的方法。 尝试按 ctrl alt F3(快捷键可能有所不同), 由桌面模式进入命令行模式。 直接 startx 报错&#xf…

批量删除推文_如何搜索(和删除)您的旧推文

批量删除推文“The internet never forgets” is an aphorism that isn’t entirely true, but it’s worth thinking about whenever you post to social media. If you think your Twitter profile needs a bit of a scrub, here’s how to search and delete those old twee…

[USACO13JAN] Cow Lineup (单调队列,尺取法)

题目链接 Solution 尺取法板子,算是复习一波. 题中说最多删除 \(k\) 种,那么其实就是找一个颜色种类最多为 \(k1\) 的区间; 统计一下其中最多的颜色出现次数. 然后直接尺取法,然后每次对于 \(col[r]\) 进行统计,时间复杂度 \(O(n)\) . Code #include<bits/stdc.h> using …

智能记忆功能nest_如何设置和安装Nest Protect智能烟雾报警器

智能记忆功能nestIf you want to add a bit more convenience and safety to your home’s smoke alarm setup, the Nest Protect comes with a handful of great features to make that a reality. Here’s how to set it up and what all you can do with it. 如果您想为您的…

网格自适应_ANSYS 非线性自适应(NLAD)网格划分及应用举例

文章来源&#xff1a;安世亚太官方订阅号&#xff08;搜索&#xff1a;Peraglobal&#xff09;在复杂的结构设计分析中&#xff0c;通常很难确定在高应力区域中是否生成适当的细化网格。在做非线性大应变分析仿真时&#xff0c;可能由于单元变形过大&#xff0c;导致网格畸变&a…

js继承优化

在看《js设计模式》中&#xff0c;作者提到了js中的两种继承方式&#xff1a;类继承 或 原型继承&#xff0c;或许是本人才疏学浅&#xff0c;竟发现一些问题。 一、类继承 思路&#xff1a;作者的思路是使用基于类来继承&#xff0c;并且做了一个extend函数&#xff0c;在第一…

python---[列表]lsit

内置数据结构&#xff08;变量类型&#xff09; -list -set -dict -tuple -list&#xff08;列表&#xff09; -一组又顺序的数据组合 -创建列表 -空列表 list1 []        print(type(list1))        print(list1)        list2 [100]       …

唤醒计算机运行此任务_如何停止Windows 8唤醒计算机以运行维护

唤醒计算机运行此任务Windows 8 comes with a new hybrid boot system, this means that your PC is never really off. It also means that Windows has the permission to wake your PC as it needs. Here’s how to stop it from waking up your PC to do maintenance tasks…