字符编码知识梳理

[toc]

字符编码:

字符编码(英语:Character encoding)、字集码是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。

字符编码的种类和进化流程

注意:上图中的扩展ascii表和gb3212等编码方式到unicode编码方式中间的箭头,仅仅表示编码的历史进化,而不是unicode来自gbk等编码方式

常用转换关系:
gbk<=======>unicode
utf-8<=======>unicode

就是通过以上的转换,将GBK编码方式的文件,转换成UTF-8格式的

在哪里需要字符编码的转换?

了解了字符编码的种类之后,我们需要了解,在什么地方,使用什么样的编码,以及为什么要使用这些编码方式。

输入保存至计算机流程

上图表示了计算机解读和存储我们在编辑器中输入字符的过程。可能中间部分的表述并不是很准确(也可以是gbk,主要取决于编辑器的编码方式),但是能大致的说明“明文————>高低电平”的转换过程。

在这里我们需要特别注意的是文本编辑器存储到内存过程中,是不是内存中只能存在unicode方式的编码。

解释器读写python文件流程

python默认的编码

  1. python2 默认使用ascii

  2. python3 默认使用utf-8

两种python的数据类型以及对应的存入数据

数据类型:存入数据(默认编码为xxxx的二进制数)

  • python2.x:
    1.str(字符串):bytes
    2.unicode(字节串):unicode

  • python3.x:
    1.str(字符串):unicode
    2.bytes(字节串):bytes

首先解决一下“什么是字节串?”这个问题:
python2.x中str的类型存入数据为bytes(这也是为什么在出现python2的unicode错误时,在原定义的字符串前添加一个‘u’,就有可能解决问题)。bytes代表的是(二进制数的序列),通过ascii编码后才是我们看到的字符形式,如果我们单独取出一个字节,可以发现它的切片是一个数字
print(b'12ffse'[0])

由此也可以推出,字节类型只能允许ascii字符?

简单来说就是把人类通用的语言符号翻译成计算机通用的对象,而反向的翻译过程自然就是解码了。Python 中的字符串类型代表人类通用的语言符号,因此字符串类型有encode()方法;而字节类型代表计算机通用的对象(二进制数据),因此字节类型有decode()方法

为什么说python3规范了默认str的字符编码是unicode使编码更加规范方便了呢?
可以参考一下上方的unicode和utf8以及gbk之间的转换关系。
同时测可以测试一下以下代码:
print(type('hello'+u'world'))
(在python2环境中运行)

相同的方式,在python3中可以这样实验:
print('hello'+b'world')

这个实验的目的就是:在不同的两个解释器中,拼接两个不同编码类型的字符串。
从而可以看出python2在字符编码上的“宽容”容易造成一些未知错误。而python3在字符编码方面的严格要求,决定了程序运行的规范和稳定性

更多关于字符编码理解的实验:http://python.jobbole.com/84839/

小结:

文本编辑器的编码,由文本编辑器的设置决定

语言解释器的解码方式,有语言解释器的默认设置和打开代码的抬头(python解释器默认设置第一二行能有效定义解码方式;#coding:UTF-8

如果说,语言解释器的解码方式和文本编辑器的编码不同,就会出现错误。

如果说,文本编辑器打开文件的编码和文件存储定义的解码方式不同,也会出现错误

说到错误,上面链接的作者在git上有一篇关于python中unicode正确使用方法的文章https://github.com/rainyear/pytips/blob/master/Markdowns/2016-03-17-Bytes-decode-Unicode-encode-Bytes.md ,我觉得里面例子很有意义,所以下面就是照着他的方式敲一遍实验代码用于明确python中的编码错误。

python 中的unicode的正确用法

python编码中最常见的两个错误

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: invalid continuation byte

encode和decode

encode和decode都是翻译的过程,而ascii和unicode在本质上都像是一本将人类语言和就算计语言对应起来的字典。而且这两本本字典有厚有薄,ASCII 只包含了26个基本拉丁字母、阿拉伯数目字和英式标点符号一共128个字符,因此只需要(不占满)一个字节就可以存储,而 Unicode 则涵盖的数据除了视觉上的字形、编码方法、标准的字符编码外,还包含了字符特性,如大小写字母,共可包含 1.1M 个字符,而到现在只填充了其中的 110K 个位置。

unicode error实验

利用一个函数来展现上面的两个错误

encode error实验

def try_encode(s, encoding = 'utf-8'):
    try:
        print(s.encode(encoding))
    except UnicodeEncodeError as err:
        print(err)
# 定义一个测试字符串默认编码的函数,传入默认解码方式为utf-8

s = '4b'
try_encode(s)
try_encode(s,'ascii')
# 使用ascii的方式解码

b = '城'
try_encode(b)
try_encode(b,'ascii')
try_encode(b,'GB2312')

反馈结果:

b'4b'
b'4b'
b'\xe5\x9f\x8e'
'ascii' codec can't encode character '\u57ce' in position 0: ordinal not in range(128)
b'\xb3\xc7'

结果分析:
由于 UTF-8 对 ASCII 的兼容性,"4b" 可以用 ASCII 进行编码;而 "城"不能使用ascii编码,因为它已经超出了 ASCII 字符集的 128 个字符,所以引发了 UnicodeEncodeError;而 "城" GB2312 中的码位是 b'\xd3\xea',与 UTF-8 不同,但是仍然可以正确编码。因此如果出现了 UnicodeEncodeError 说明你用错了字典,要翻译的字符没办法正确翻译成码位!

decode error实验

def try_decode(s, decoding = 'utf-8'):
    try:
        print(s.decode(decoding))
    except UnicodeDecodeError as err:
        print(err)

s = b'4b'
try_decode(s)
try_decode(s,'ascii')

b = b'\xb3\xc7'
try_decode(b)
try_decode(b,'ascii')
try_decode(b,'GB2312')
try_decode(b,'GBK')
try_decode(b,'Big5')

try_decode(b.decode('GB2312').encode())
# byte - decode - unicode - encode - byte

反馈结果:

4b
4b
'utf-8' codec can't decode byte 0xb3 in position 0: invalid start byte
'ascii' codec can't decode byte 0xb3 in position 0: ordinal not in range(128)
城
城
傑
城

一般后续出现的字符集都是对 ASCII 兼容的,可以认为 ASCII 是他们的一个子集,因此可以用 ASCII 进行解码(编码)的,一般也可以用其它方法;对于不是不存在子集关系的编码,强行解码有可能会导致错误或乱码!

实践中的注意事项:

  1. 记清楚编码和解码的方向

  2. 在python中尽量采用utf-8,输入或者输出的时候根据需求确定是否需要编码成二进制

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

推荐阅读更多精彩内容