字符编码:ASCII,Unicode 和 UTF-8

本文介绍了字符编码的基础知识,包括ASCII码、非ASCII码和Unicode的概念,以及Unicode的扩展——UTF-8。通过理解字符编码的原理,解释了为什么在处理不同语言时可能会出现乱码问题,以及UTF-8如何解决存储和识别问题,避免乱码。
摘要由CSDN通过智能技术生成

以前遇到设置字符编码格式的时候,通常都是默认按照默认设置,一直以来都没有出什么问题,所以这块一直也就没有怎么管过。夜路走多了,总会遇到鬼,昨天就被字符的编码格式给坑了。学个乖,整理下这块内容,也运气好好,发现一篇博客对这些描述的比较清楚,自己从中提取了些信息,做以记录,加深印象。

众所周知,计算机只识别二进制,所有文件存到最底层都是以不同长度的 0 和 1 排列组合保存起来的,0 和 1 都叫做二进制位,八位叫一个字节。之所以我们看到各种合适的文件,上层应用软件的功劳,为了方便人看和管理。所谓编码格式,就是一个编码规则,即文件和它的二进制之间的映射关系。有时候打开文件出现乱码,换一种编码方式就正常显示了,这是因为文件原本是以A 编码格式存成了二进制,结果你硬要以 B 编码格式打开它,二进制的数据按照 B 编码格式反向翻译出现乱码也就不足为奇了,当你换成以 A 编码格式打开它,二进制数据按照 A 编码格式反向翻译即可正常显示。所以编码格式虽是基础,但的确很重要。

当然我们只要理清概念就差不多了,具体怎么编码的前人们都已经做好了,我们需要做的就是在不同场景下,选择恰当的编码格式。

ASCII 码

在上世纪 60 年代,美国制定了一套字符编码,规定了英语字符和二进制之间的映射关系。这就是 ASCII 码,一直沿用至今。

一个字节占八位,会出现 256 中不同的 0 、1的排列组合状态,每种状态表示一个字符,那么就可以表示 256个字符。因为英语字符数量很少,也很简单,ASCII 规定了 128 个字符编码(这数量足以让英语完整表达)其中,字母大小写加上阿拉伯数字总共 62 个,其他的 加号、减号、方括号、特殊符号 等等,这些全部加起来用 0XXXXXXX 这种长度的二进制都可以表示出来。

也就是说一个字节,就可以表示一个英语字符,不同的英语字符按照 ASCII 码的规则映射的二进制位数是一定的(8位)不一样的是里面 0、1的排列组合。kangkang天朝,也是随手查了下,2010年版的 《汉语大字典》收字 60370 个字,1988 年国家语委、国家教委发布的《现代汉语常用字表》里面也有 3500 个字。中文编码是个特例,先不讨论。

非 ASCII 码

128 个字符编码足以完整表示英语,但不一定能够满足其他国家的语言表示。比如,法语字母上有注音符号,它就无法用 ASCII 码表示出来。但 ASCII 编码是没有使用字节的最高位的,所以,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号,即在原有 ASCII 码的基础上扩充下,法语中的é的编码为130(二进制10000010)。

这样的扩充的结果是:一个字节可以表示 256 个符号,其中 0–127 这部分继续沿用 ASCII 码的规则,128–255 这部分各种语言都有自己的映射规则。比如:130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。

等到天朝,256 个字符也不够用,光常用字就有三千多个。所以就选择使用多个字节表示一个符号,简体中文常见的编码方式是 GB2312,使用两个字节表示一个汉字,( 2 16 = 65536 2^{16}=65536 216=65536),两个字节理论上可以表示 65536 个汉字,可以满足日常使用了。

简单概括下:非 ASCII 编码就是 ASCII 扩充的结果。

Unicode

ASCII 码以及它的扩展已经是好几中编码格式了,所以如果不设定编码格式,就将二进制反向翻译会造成乱码。造成这种现象是因为各种语言都有自己的字符集,英语、法语、俄语、汉语等等,各自的字符集都不一样,所以大家都制定了适合各自语种的编码格式用来映射二进制。那有没有一种符号集,将世界上所有的符号都纳入其中,每一个符号都给与一个独一无二的编码,那这样的话,乱码问题就会消失了。Unicode 就是基于这个目的而研发的,并与 1994 年被正式公布,它把所有语言都统一到一套编码里,这样就不会再有乱码问题了。

全部的符号对应表查询:https://home.unicode.org/

中文编码对应表查这里:http://www.chi2ko.com/tool/CJK.htm

但 Unicode 只是一个符号集,它规定了每个符号对应的二进制编码是多少。但是没有规定这个二进制该如何存储。比如:汉字 对应的编码是 4E30,英语:A 对应的编码是 0041 用两个字节表示,A 其实用一个字节就可以表示了,但是在 Unicode 中为了统一,依旧选择用两个字节的编码表示。

那这里就有一个存储的问题了,如果英语直接使用两个字节存储,其实是存了好多 0,不仅浪费了存储资源,而且文本文件的大小也会是原来的 2 倍。如果单纯为了迁就英文都选用一个字节,那汉语就不能正确存储了。更要命的是,打开文件时如果遇到 0010 0101 (这个字节是我瞎写的)这样的二进制,是该把它当做两个单独的字节反向翻译成两个英文字母呢,还是应该把它当做字节组反向翻译成一个汉字。

UTF-8

UTF-8 就是解决了上面的两个问题。UTF-8 的英文全称是 8-bit Unicode Transformation Format ,根据名字它将原本的 Unicode 码给 transformation 了下,这种转化将原本的 Unicode 码采用 1~4 个字节进行表示,这些字节有两部分构成:标记位和数据位 ,其中标记为使得计算机看到这个标记就知道要读取多少个字节,该反向翻译成什么字符。

当然 UTF-8 的数据格式到底是什么样子的,我没有细看过,有兴趣的可以看这里:https://baike.baidu.com/item/UTF-8

  • 本以为是个青铜,写几句就交代清楚了。没想到是钻石,查资料、整理思路、再写出来也花了好几个小时的时间,到这里已经不只是简单的摘抄了。

  • 填坑、打怪、升级!

  • 还有就是,太浮躁了,我想静静。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值