作为一个程序员,你应该知道的编码知识

栏目: IT技术 · 发布时间: 4年前

内容简介:花括号MC(huakuohao-mc):关注JAVA基础编程及大数据,注重经验分享及个人成长。

花括号MC(huakuohao-mc):关注 JAVA 基础编程及大数据,注重经验分享及个人成长。

在谍战剧里,我们经常看到这样一个桥段,特工人员,千辛万苦拿到一条信息,打开一看是一串数字,然后赶紧跑到一个秘密地方,拿出一个密码本(也可能是一本唐诗选),按照一定规则(只有自己人知道),比如第一个数字表示页数,第二个数字表示行数,第三个数字表示第几个字,逐一将信息翻译出来。如果这个过程中用了错误的密码本,或者不知道规则,那么将会解码失败。

计算机的编解码过程跟上面的过程是一样一样的。

计算机只认 01 ,所有的影像和字符最终都会转换成计算机能够认识的二进制。一个二进制位(bit)可以表示两种状态 01 ,一个字节(byte)由八个二进制位组成,所以一个字节一共可以表示256( 2^8 )种状态。如果我们规定每种状态代表一个字符,那么一个字节就可以表达出 256 个字符。

ASCII

计算机是由美国人发明的,所以在最初设计编码的时候,就只考虑了英文的编码。英文字符很少,加上一些特殊字符,一共也就100个左右,确切的说是128个。这样的话用一个字节进行编码就完全够了,不仅够用了,而且还富裕出一位,即第一位一直没有参与编码,统一定为 0 。这就是所谓的 ASCII 编码。在 ASCII 编码中,空格 SPACE32 (二进制 00100000 ),大写的字母 A65 (二进制 01000001 )。

非ASCII

随着计算机的普及,欧洲也开始普及计算机,欧洲人发现 ASCII 规定的 128 个字符不能满足他们的使用,比如,在法语中,字母上方有注音符号,就无法用 ASCII 码表示。于是,一些欧洲国家就决定,把字节中闲置的第一位编入新的符号。比如,法语中的 é 的编码为 130 (二进制 10000010 )。这样一来,这些欧洲国家使用的编码体系,最多可以表示 256 个符号。这就是大家经常见到的 ISO-8859-1 编码,也叫 Latin1 编码。

中文编码

随着计算机的普及,国人也开始使用计算机,但是发现按照之前的编码方式,根本就没有汉字什么事儿,也就是计算机根本没办法认识汉字。

GB2312

为了能够让计算机认识汉字,我们决定对汉字进行编码,本着敢想敢干的精神,我们规定用两个字节表示一个汉字。

具体规则是这样的:一个小于 127 的字节代表的意义与原来的 ASCII 相同,但两个大于 127 的字节连在一起时,就表示这是一个汉字,前面的一个字节称为高字节,后面一个字节称为低字节,这样我们就可以组合出 6763 个简体汉字。这就是大家常说的 GB2312 编码。

GBK

很显然 GB2312 编码的 6763 个汉字,并不能适应所有的使用场景,比如“喆”字就不再其中,于是在 GB2312 的基础上又进行了新的扩展,规定只要第一个字节是大于 127 的就OK,至于第二个字节是大于 127 还是小于 127 都无所谓了。经过这样的改动之后,收录的汉字及符号就可以达到 2W 多个,这就是我们常说的 GBK 编码。

再后来,人们继续对第二个字节进行扩展,发展出了 GB18030 编码,比 GBK 又多出了一些字符编码。

至此,所有的汉字编码都是用两个字节表示的,但是英文是用一个字节表示。上了一些年纪的 程序员 都体验过,一个汉字算两个英文字符的经历。

BIG-5

上面提到的都是简体中文编码,虽然 GBKGB18030 包含了部分繁体字,但是也不全面,于是台湾同胞就发了专门支持繁体字的 Big5 编码,也就是大家经常说的大五码。

一个小问题

不知道大家有没有注意到一个问题,在单字节编码的时候,对于那些大于 127 小于 256 的编码,在不同的国家代表的字母很可能不一样。比如, 130 在法语编码中代表了 é ,在希伯来语编码中却代表了字母 Gimel (ג) ,在俄语编码中又会代表另一个符号。在汉字的双字节编码中也存在这样的问题,比如 BIG5 编码跟 GBK 编码都是双字节编码,但是代表的汉字却不一样。

这就相当于,同样一串二进制数值,A特工组织按照他们的规则解析出来可能是“你好”,而B特工组织按照他们的规则解析出来可能是“滚蛋”。特工组织之间的翻译标准不一样是相当有必要的,但是计算机的编码规则如果各不相同就比较麻烦了。比如你跟台湾的志玲姐姐聊天,志玲姐姐用 BIG5 编码给你发了一封信,然后你用 GBK 去解码,……,也许就没有然后了。

Unicode

为了解决上面的问题,有个叫 ISO 的国际标准组织,决定放弃所有区域性编码,如 BIG5GBK 等,重新制定一个新的编码,这个编码集将包含所有字符的编码,这样大家就都统一了,这套编码的英文全称“Universal Multiple-Octet Coded Character Set”,简称UCS, 俗称 “Unicode“。 Unicode 的出现相当于秦始皇对度量衡跟货币进行了统一。

Unicdoe 按照日常字符的使用频繁度划分了 17 个平面,编号为 0-160 号平面称为基本多语言平面(Basic Multilingual Plane,简称 BMP ),包含了日常使用最频繁的字符,编码范围从 0000FFFF ,这样该平面可以表示 2^16=65536 个字符;其它平面的编码范围也是从 0000FFFF ,所以其它平面也可以编码 65535 个字符,这样 17 个平面一共可以编码 17×65,536 = 1,114,112 个符号。

我们最常用的 Unicode 编码使用的是多语言平面的编码,即所有字符都用两个字节进行编码(其它平面可能需要三个或四个字节)。举个例子比如中国的'中'字 Unicode 码是 4E2D ,小写'a'的 Unicode 码是 0061 .

这里面存在两个问题,如果所有英文字符都是按照 Unicode 编码,那么会出现浪费存储空间的问题。明明一个字节可以搞定的事情,偏偏要用两个字节。

第二个问题就是计算机如何知道这是 Unicode 编码还是 ASCII 编码,也就是 2 个字节表示的一个字符,还是 2 个字符呢。

UTF

UTF 的全称是 Unicode Transformation Format ,也就是 Unicode 的转换格式。上面提到了,如果直接使用 Unicode 码进行存储会存在浪费空间的问题,而 UTF-8 的出现就是为了解决该问题, UTF-8 使用变长的方式存储 Unicode 码,也就是英文字符继续使用一个字节进行存储,但是汉字要使用 3 个字节。那么 UTF-8 是如何做到的呢。

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

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

下表总结了编码规则,字母 x 代表可用的编码位。

Unicode符号范围(十六进制) UTF-8编码方式(二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

根据上表,对 UTF-8 编码进行解读会发现,如果一个字节的第一位是 0 ,则这个字节单独就是一个字符;如果第一位是 1 ,则连续有多少个 1 ,就表示当前字符占用多少个字节。

举个例子

假设“hello世界”这样一个字符串,他们的 Unicode 的编码分别是

1h--0068
2e--0065
3l--006C
4l--006C
5o--006F
6世--4E16
7界--754C

按照 UTF-8 的编码规则可以得到如下 UTF-8 编码

1h--01101000
2e--01100101
3l--01101100
4l--01101100
5o--01101111
6世--11100100-10111000-10010110
7界--11100111-10010101-10001100

可以看到用 UTF-8 编码之后,英文字符占用一个字节,而汉字占用了三个字节,一共需要 11 个字节,而如果直接存储 Unicode 码则需要 14 个字节。 UTF-8 编码对于英文来说节省了很大空间,但是对于中文来说增加了空间。

Little endian 和 Big endian

上面提到 Unicode 是用两个字节表示字符,如果第一个字节在前,就是"大端方式"(Big endian),第二个字节在前就是"小端方式"(Little endian)。'世'字的 Unicode 码是 4E16 ,一个字节是 4E ,一个字节是 16 , 存储的时候如果 4E 在前就是大端存储,如果是 16 在前就是小端存储。

那么计算机是怎么知道一个文件是采用哪种编码方式呢?

Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用 FEFF 表示。这正好是两个字节,而且 FFFE1

如果一个文本文件的头两个字节是 FE FF ,就表示该文件采用大头方式;如果头两个字节是 FF FE ,就表示该文件采用小头方式。

总结

UTF-8 编码是基于 Unicode 字符集的一种编码实现。现在几乎所有的编程语言和操作系统都支持 Unicode 编码,使用 Unicode 编码之后,再也不会出现上文提到的一个汉字等于两个英文字符的尴尬局面。

GBKBIG5 等都属于区域性编码只能在固定范围内使用,比如 GBK 只适合在简体中文环境使用,虽然 GBK 相比于 UTF-8 更节省空间,但现在全世界都变成地球村了,所以还是建议大家都使用 UTF-8 编码。

ANSI :在 window 下,如果我们用记事本打开文档,经常会见到 ANSI 编码方式,这是 Windows 默认的编码方式。对于英文文档采用 ASCII 编码,对于简体中文文档采用 GB2312 编码(只针对 Windows 简体中文版,如果是繁体中文版会采用 Big5 码)。

·END·

花括号MC

Java·大数据·个人成长

作为一个程序员,你应该知道的编码知识

微信号:huakuohao-mc

点一下你会更好看耶

作为一个程序员,你应该知道的编码知识


以上所述就是小编给大家介绍的《作为一个程序员,你应该知道的编码知识》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

机器学习系统设计

机器学习系统设计

[德] Willi Richert、Luis Pedro Coelho / 刘峰 / 人民邮电出版社 / 2014-7-1 / CNY 49.00

如今,机器学习正在互联网上下掀起热潮,而Python则是非常适合开发机器学习系统的一门优秀语言。作为动态语言,它支持快速探索和实验,并且针对Python的机器学习算法库的数量也与日俱增。本书最大的特色,就是结合实例分析教会读者如何通过机器学习解决实际问题。 本书将向读者展示如何从原始数据中发现模式,首先从Python与机器学习的关系讲起,再介绍一些库,然后就开始基于数据集进行比较正式的项目开......一起来看看 《机器学习系统设计》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具