编码方式的区别以及文本在python2中的应用

背景:

        文本以及字符串处理在网络应用中随处可见,面对不同的用户接口调用方,以及不同的我们需要调用的接口,可能都会有不一样的编码规范。

        而我在以前的开发中,对于字符串的处理经常会是以猜的方式来处理,encode、decode等各种方式都试一遍,发现哪个能解决问题就用哪个,从来没有真正的了解字符串相关的原理与逻辑。

        所以,最近通过阅读《Fluent Python》一书以及一些源码、博文,好好了解了一下字符相关的原理以及在开发中的应用,记录一下学习过程中觉得有用的地方以及一些理解。


ASCII,Unicode 和 UTF-8之间的关系

ASCII码

        ASCII是最早的编码,美国发明,使用一个字节8位,最多可以展示255个字符,但是ASCII编码中第一位没有使用,仅用字节的后七位表示了127个字符。

Unicode 

        Unicode是一种所有符号的编码,包含了世界上各种语言的符号,目前有一百多万个符号在这个集合中。

        但是Unicode只是一个集合,是把所有的字符就放在这个集合里,它规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

        因为Unicode表示的字符大部分需要两个字节,甚至有的会更多。如果没有规定的存储方式,或者合适的存储方式,统一用两个字节来表示所有的字符,那么ASCII码中本来可以用一个字节表示的英文字母,就也需要两个字节表示(第一个字节全部是0),这样如果目标全是英文,就相当于占用的存储空间直接翻倍了。

UTF-8

        UTF-8(UTF-16)是 Unicode 的实现方式之一。UTF-8是目前使用最广的一种 Unicode 的实现方式。

        UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,英文字母被编码成1个字节,汉字通常是3个字节,少量很生僻的字符会被编码成4-6个字节。这样在全是英文的地方,就不会用浪费空间,对于需要多字节的汉字,也能正常展示。

        UTF-8的编码规则有一下两条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

        如上图所示为Unicode符号与UTF-8的对应关系举例。

        识别UTF-8有多少字节的核心是:如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

        因为UTF-8在只使用一个字节的时候,和ASCII是一样的,所以UTF-8是可以兼容ASCII的。


 综上所述,有如下结论:

        Unicode和ASCII是同一种概念,是是一种编码方式。而UTF-8,UTF-16等是一种存储方式,在存储和传输上节约空间、提高性能的一种编码形式。


字符相关在Python中的使用

《Fluent Python》:

Unicode 标准把字符的标识和具体的字节表述进行了如下的明确区分。

        字符的标识,即码位,是0~1 114 111的数字(十进制),在Unicode 标准中以4~6 个十六进制数字表示,而且加前缀“U+”。例如,字母A的码位是U+0041,欧元符号的码位是U+20AC,高音谱号的码位是U+1D11E。在Unicode 6.3中(这是Python 3.4使用的标准),约10%的有效码位有对应的字符。

        字符的具体表述取决于所用的编码。编码是在码位和字节序列之间转换时使用的算法。在UTF-8编码中,A(U+0041)的码位编码成单个字节\x41,而在UTF-16LE编码中编码成两个字节\x41\x00。再举个例子,欧元符号(U+20AC)在UTF-8编码中是三个字节——\xe2\x82\xac,而在UTF-16LE中编码成两个字节:\xac\x20。

        把码位转换成字节序列的过程是编码,把字节序列转换成码位的过程是解码。通俗点讲,在开发过程中会碰到两种字符:存储在机器中的是字节序列,展现出来是Unicode字符(人类可读的文本)。将机器读取的文本转为人类可读的文本就是解码(decode),将人类可读的文本转为给机器读取的文本就是编码(encode)。

在我们项目中的应用

        在开发过程中,为了避免对接不同的接口或者平台的时候出现编码方式不同造成的报错,我们需要在整个系统中都统一同一套编码方式。

        我们使用tornado框架,框架中get_argument方法默认会将拿到的参数转为unicode:

        在我们项目的utils.py文件中,一般也都会有针对字符串的编码转换的方法可以调用:

         在编写脚本的时候,在文件顶部定义脚本的编码方式:

        在具体使用的地方,也要根据具体需求将文本解码为我们所使用的UTF-8。

Python2规范化字符编码

        Python2(从2.5开始)则默认使用ASCII。因此直接创建的字符串一般默认为ASCII,如果调用接口或者进行需要UTF-8的处理,需要对字符串进行解码。

        在进行字符串处理的时候,可能会遇到无法编码或者解码的报错,要根据具体情况处理。

        一般比较常见的是两种错误:UnicodeEncodeError(把字符串转换成二进制序列时),UnicodeDecodeError(把二进制序列转换成字符串时)。这种情况是因为目标编码方式没有没有我们需要编码/解码的字符串中的某个字符或者符号。在进行测试或者自己的一些简单开发的时候,可以在使用encode的时候,增加对errors的指定处理方式来跳过(实际开发中,需要让异常正常抛出):

city.encode('cp437', errors='ignore') 跳过错误。

city.encode('cp437', errors='replace') 将无法编码的字符用?代替。

city.encode('cp437', errors='xmlcharrefreplace')把无法编码的字符替换成XML实体。

        对于有些情况,还可能出现音字符的情况,对于同样一个字符,可能会有不同的Unicode编码方式。如下图:

        此时,可以使用unicodedata.normalize函数对字符串进行Unicode规范化。

        这个函数的第一个参数是这4个字符串中的一个:'NFC'、'NFD'、'NFKC'和'NFKD'。我们可以主要使用前两个:NFC(Normalization Form C)使用最少的码位构成等价的字符串,NFD把组合字符分解成基字符和单独的组合字符。具体使用如下:

        unicodedata中的combining()函数可以用来判断一个字符是否是音字符,可以用来将文本中的音字符全部过滤掉。

        在处理字符串的时候,还有一些方法可以直接对字符串进行简单判断,灵活运用起来会大大提高开发效率。包括isdigital(), startswith(),endswith()等。

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

推荐阅读更多精彩内容

  • 字符是用户可以读写的最小单位。计算机所能支持的字符组成的集合,就叫做字符集。字符集通常以二维表的形式存在。二维表的...
    刘惜有阅读 8,068评论 2 14
  • 字符集和编码简介 在编程中常常可以见到各种字符集和编码,包括ASCII,MBCS,Unicode等字符集。确切的说...
    兰山小亭阅读 8,452评论 0 13
  • UTF-8 编码提供了一种简便而向后兼容的方法, 使得那种完全围绕 ASCII 设计的操作系统, 比如 Unix,...
    谢大见阅读 4,654评论 0 3
  • 父亲年轻的时候是村子里出了名的胆大心细不怕事。 那时因为家里孩子多,他又是老大的缘故,初中毕业便辍学在家。十七八岁...
    淡淡青莲阅读 375评论 8 10
  • 本文参与#漫步青春#征文活动,作者:夏梁凡,本人承诺,文章内容为原创,且未在其它平台发布。 走走停停 默数着脚下的...
    想做诗人的数学系渣渣阅读 393评论 0 1