[问题记录]字符编码、Python字符串以及常见异常

在讲 Python 字符串之前先了解一下常用的字符编码

常用三种字符编码发展

常用的三种字符编码与特点:

  1. ASCII码 :最早
  2. Unicode : 把所有语言都统一到一套编码
  3. UTF-8 : 相对于Unicode节省空间,并兼容ASCII码

发展由来:
最早的编码是「ASCII码」,其编码范围为 0 - 127,即只能存放127个字符,包括了大小写英文字母、数字和一些符号。每个字符占一个字节。

这样,ASCII 码只能处理英文,那么其他语言字符呢?

其他语言字符编码则是在 ASCII 码基础上扩展。例如,要处理一个中文字符一个字符是不够的,且不能与ASCII码冲突,所以中国制定了「GB2312码」,把中文编进去。但又由于全世界有很多语言,如果都各编各的话,在互相交流就容易产生乱码。

此时「Unicode」把所有语言都统一到一套编码。Unicode字符通常占 2 个字节或以上。Unicode至少占用 2 个字节,这又带来了问题:原本ASCII码中占 1 个字节的A到Unicode要占 2 个字节,就浪费了一倍的存储空间。

为了节省空间,人们又发明了可变长「UTF-8」,它对一个不同范围的
Unicode 字符使用不同长度的编码,如英文字母被编码为 1 个字节,汉字通常为 3 个字节。可以看出,UTF-8包含了ASCII码。故此,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

三种编码的对比

最后,用一幅图来总结这三种编码演变过程


常用三种字符编码演变过程

计算机系统通用的字符编码工作方式

现在计算机系统通用的字符编码工作方式:

在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,一般就转换为UTF-8编码。

举个例子,当你记事本选择UTF-8格式保存时,记事本的内容按照UTF-8编码存放在硬盘中。而当你在编辑记事本内容(即内容被读取到内存中)
时,UTF-8的字符会被转换Unicode字符放在内存中。

Python2.x 字符串

因为 Python 诞生比 Unicode 早,所以一开始 Python 只支持 ASCII字符串,后面才加上Unicode字符串。故此,Python2.x的字符串的编码方式有两种 :

  1. 按ASCII编码,它是字符串默认的编码方式,对应的字符串类型是str
  2. 按Unicode编码,对应的字符串类型是unicode

举个例子

>>>type('hello')
<type 'str'>
>>> type(u'hello')
<type 'unicode'> 

正因为两种编码方式共存并且我们经常会用到中文字符不包含在 ASCII
中,稍有转换不对就会抛出异常。以下两个异常最为多见:

第一种:「SyntaxError」: Non-ASCII character '\xe4' ...

问题描述
举个例子,在一个 .py 文件中

print u'中'

SyntaxError: Non-ASCII character '\xe4' in file E:\test.py on line 1, 
but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

问题产生的原因
根据官方文档的解释是, Python2.x 的解释器默认按 ASCII 编码去读取源代码,而u'中'并不是 ASCII 编码的字符串,所以解释器没法正确读取源代码。

总之,「如果解释器读取源代码按照默认编码方式 ASCII 的话,文件存在中文字符就会报错」

解决方法
官方文档给出的解决方案是在 .py 文件的第一行或第二行加上

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

用于申明 Python2.x 解释器按 UTF-8 编码读取文件。

PS :
这里需要注意一下,源代码文件按照 UTF-8 格式存储,仅代表在硬盘中字符按 UTF-8 编码存储。并不是指定 Python解释器读取源代码的编码方式。
但如果不按照 UTF-8 格式存储文件,可能下次打开文件,文件中的中文字符会变成乱码。

第二种:「UnicodeEncodeError」: 'ascii' codec can't encode characters ...

问题描述
举个例子,在一个 .py 文件中

# -*- coding: utf-8 -*-
str(u'中')

Traceback (most recent call last):
 File "E:\test.py", line 3, in <module>
   str(u'中文')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

问题产生的原因
从异常的提示信息,知道了因为 ASCII 编解码器不能编码 Unicode 字符。
上面说到,Python2.x str() 的编码是 ASCII, ASCII 编解码器只通过范围0-127的字符,超过范围的字符就会报错。其中 u'中' 是 Unicode 且占2个字节,已经超过了127的范围。

总之,「如果存放将 Unicode 字符串强行转换为默认的字符串(str类型)的时候,就会报这种异常」

解决方案

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

str(u'这')

通过 sys 模块修改解释器默认编码格式后,将默认编码格式也改成 UTF-8, 就变成 Unicode 转 UTF-8,此时转换就没问题了。
放在这个例子中,str是默认的字符串类型,编码方式是 ASCII,修改了解释器的默认编码格式,str的编码方式也跟着改变。

Python3.x 字符串

在 Python3 中,默认字符串编码改为了 Unicode,这样使得 Python 更好地支持多语言了。同样, Python3 依旧支持两种字符串,

  1. Unicode 字符串,是默认的编码格式,不需要在前面加u,对应的类型是 str
  2. Byte 字符串,编码格式是 ASCII,需要在字符串面前加b,例如b'abc'

需要注意的是,
默认情况下,Python 源文件是 UTF-8 编码。在此编码下,全世界大多数语言的字符可以同时用在字符串、标识符和注释中 — 尽管 Python 标准库仅使用 ASCII 字符做为标识符,这只是任何可移植代码应该遵守的约定。如果要正确的显示所有的字符,你的编辑器必须能识别出文件是 UTF-8 编码,并且它使用的字体能支持文件中所有的字符。 Python3 源文件的第一行或者第二行依旧需要加上

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

通过此声明,源文件中所有的东西都会被当做用 encoding 指代的 UTF-8 编码对待。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容