一、了解编码

  • 在计算机中存储的数据都是01二进制的数据串,我们再电脑屏幕上看到的一切可视化的东西最终在计算机存储的都是01二进制串,现在看到我博客上的文字也是。
  • 这里就需要一个映射关系,将我们看到的看到的字符、图片、视频转换成对应的二进制,存储到计算机中,以便于计算机能够识别。这就是我们要将的编码。
  • 图片和视频首先会转换成字符流,然后按照编码转换成字节流,存储到计算机中。
  • 举一个例子:在ASCLL码表中,字符’a‘对应的是97,二进制是01100001,如果我们在编辑器或者其他软件中输入字母a,按键盘a,那么输入法就会告诉操作系统,在计算机中调用97,然后就会显示a字符。
  • 也就是说编码表在我们在计算机屏幕看到的数字和计算机底层之间架起了一个桥梁。至关重要!

二、编码的历程

1、开始
  • 最早出现的是ASCLL码,是由美国人制定的,这种编码采用的是1个字节表示一个字符,也就是一个字符是八个二进制位,这里一共可以表示256个字符。起初,表示英文中所有的字符一共用了128位字符。事实上还剩下了一百多个字符空间。这128个字符中包含了数字、字母以及常用字符,例如:A是65,对应的二进制数为0100 0001。而且呢,这个128个字符只用了八位二进制数中的后七位,最前面的一位统一为0。
2、问题初现
  • 但是很快就暴露出了问题,这128个字符表示英文没有任何问题,但是要是表示其他国家的语言就不够了。率先是欧洲决定利用起来前一位,这样就可以表示256个字符了,而紧接着又出现了一个问题,就是不同国家的同一个码点(八位二进制数)表示的符号可能不同,例如144 在阿拉伯人的 ASCII 码中是 گ,而在俄罗斯的 ASCII 码中是 ђ。 所以呢,最后人们在0-127号字符上面达成了一致,对于128 - 255号字符就尽情发挥了,这时候的码点还是一个字节。
3、再遇到波折
  • 随着计算机的兴起,传入亚洲国家,亚洲国家有更多的字符需要存储,这样256个字符就放不下这些符号了,这时候人们决定用两个字节一共十六位,最多可以表示65535个字符。来存储全世界的字符。但是此时各个国家的编码还是不一样的。如ASCII、GB2312等。
4、程序员的噩梦
  • 各种各样的编码方式成了系统开发者的噩梦,因为他们想把软件卖到国外,但是由于编码不同,一台计算机根本无法表示所有国家的编码。于是,他们提出了一个“内码表”的概念,可以切换到相应语言的一个内码表,这样才能显示相应语言的字母。在这种情况下,如果使用多语种,那么就需要频繁的在内码表内进行切换。这样依然很麻烦。
5、解决
  • 最终,美国人决定设计一种标准方案来展示世界上所有语言中的所有字符,Unicode诞生了。Unicode 给所有的字符指定了一个数字用来表示该字符。规定了符合对应的二进制代码,至于这个二进制代码如何存储则没有任何规定。它的想法很简单,就是为每个字符规定一个用来表示该字符的数字,仅此而已。具体是怎样的对应关系,又或者说是如何进行划分的,就不是我们考虑的问题了,

三、Unicode 编码方案

  • Unicode 当然是一本很厚的字典,记录着世界上所有字符对应的一个数字。以汉字“汉”为例,它的 Unicode 码点是 0x6c49,对应的二进制数是 110110001001001,二进制数有 15 位,这也就说明了它至少需要 2 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节。
1、空间浪费?
  • 大家可以试想一下,有的字符需要两个字节、有的需要三个四个字节,那计算机如何去分辨该字节是几个字节的字符呢?大家第一个想到的可能是全部采用4个字节的编码,毕竟这个可以表示上亿个字符了。但是如果一个美国的新闻发布网站,全英文表示(前面已经说了代码单元也就是存储为一个字节就可以表示所有的英文字符),现在前面三个字节都是0,文件大小变成了之前的四倍或者三倍,这样浪费掉了大量的存储空间。
2、UTF系列编码什么鬼?
  • 为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,但是一般的字符两个字节就可以轻松解决了,只有一些其他小国家的特殊字符才采用UTF-32编码。
3、UTF-8编码
  • UTF-8 是一个非常惊艳的编码方式,漂亮的实现了对 ASCII 码的向后兼容,以保证 Unicode 可以被大众接受。

  • UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。编码规则如下:

  • 对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。这意味着 ASCII 码那个年代的文档用 UTF-8 编码打开完全没有问题。

  • 对于需要使用 N 个字节来表示的字符(N > 1),第一个字节的前 N 位都设为 1,第 N + 1 位设为0,剩余的 N - 1 个字节的前两位都设位 10,剩下的二进制位则使用这个字符的 Unicode 码点来填充。

  • 编码规则如下:

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
4、插入一只广告
  • 这里的除x外都是控制位,真正的表示位的只是x,第一个字节0xxxxxxx,可以容纳7个二进制位,第二个可以容纳11个二进制位,以此类推,然后计算左边的范围。
5、编码与解码
  • 根据上面编码规则对照表,进行 UTF-8 编码和解码就简单多了。下面以汉字“汉”为利,具体说明如何进行 UTF-8 编码和解码。“汉”的 Unicode 码点是 0x6c49(110 1100 0100 1001),通过上面的对照表可以发现,0x0000 6c49 位于第三行的范围,那么得出其格式为 1110xxxx 10xxxxxx 10xxxxxx。接着,从“汉”的二进制数最后一位开始,从后向前依次填充对应格式中的 x,多出的 x 用 0 补上。这样,就得到了“汉”的 UTF-8 编码为 11100110 10110001 10001001,转换成十六进制就是 0xE6 0xB7 0x89。
  • 解码的过程也十分简单:如果一个字节的第一位是 0 ,则说明这个字节对应一个字符;如果一个字节的第一位1,那么连续有多少个 1,就表示该字符占用多少个字节。
UTF-16编码
  • 在了解 UTF-16 编码方式之前,先了解一下另外一个概念——“平面”。

  • 在上面的介绍中,提到了 Unicode 是一本很厚的字典,她将全世界所有的字符定义在一个集合里。这么多的字符不是一次性定义的,而是分区定义。每个区可以存放 65536 个(2^16)字符,称为一个平面(plane)。目前,一共有 17 个(2^5)平面,也就是说,整个 Unicode 字符集的大小现在是 2^21。

  • 最前面的 65536 个字符位,称为基本平面(简称 BMP ),它的码点范围是从 0 到 2^16-1,写成 16 进制就是从 U+0000 到 U+FFFF。所有最常见的字符都放在这个平面,这是 Unicode 最先定义和公布的一个平面。剩下的字符都放在辅助平面(简称 SMP ),码点范围从 U+010000 到 U+10FFFF。

  • 基本了解了平面的概念后,再说回到 UTF-16。UTF-16 编码介于 UTF-32 与 UTF-8 之间,同时结合了定长和变长两种编码方法的特点。它的编码规则很简单:基本平面的字符占用 2 个字节,辅助平面的字符占用 4 个字节。也就是说,UTF-16 的编码长度要么是 2 个字节(U+0000 到 U+FFFF),要么是 4 个字节(U+010000 到 U+10FFFF)。那么问题来了,当我们遇到两个字节时,到底是把这两个字节当作一个字符还是与后面的两个字节一起当作一个字符呢?

  • 这里有一个很巧妙的地方,在基本平面内,从 U+D800 到 U+DFFF 是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。

  • 辅助平面的字符位共有 2^20 个,因此表示这些字符至少需要 20 个二进制位。UTF-16 将这 20 个二进制位分成两半,前 10 位映射在 U+D800 到 U+DBFF,称为高位(H),后 10 位映射在 U+DC00 到 U+DFFF,称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。

  • 因此,当我们遇到两个字节,发现它的码点在 U+D800 到 U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00 到 U+DFFF 之间,这四个字节必须放在一起解读。

  • 接下来,以汉字"?"为例,说明 UTF-16 编码方式是如何工作的。

  • 汉字"?"的 Unicode 码点为 0x20BB7,该码点显然超出了基本平面的范围(0x0000 - 0xFFFF),因此需要使用四个字节表示。首先用 0x20BB7 - 0x10000 计算出超出的部分,然后将其用 20 个二进制位表示(不足前面补 0 ),结果为0001000010 1110110111。接着,将前 10 位映射到 U+D800 到 U+DBFF 之间,后 10 位映射到 U+DC00 到 U+DFFF 即可。U+D800 对应的二进制数为 1101100000000000,直接填充后面的 10 个二进制位即可,得到 1101100001000010,转成 16 进制数则为 0xD842。同理可得,低位为 0xDFB7。因此得出汉字"?"的 UTF-16 编码为 0xD842 0xDFB7。

  • Unicode3.0 中给出了辅助平面字符的转换公式:

H = Math.floor((c-0x10000) / 0x400)+0xD800L = (c - 0x10000) % 0x400 + 0xDC00
  • 根据编码公式,可以很方便的计算出字符的 UTF-16 编码。

史上最好理解的Unicode编码讲解(Unicode的前世今生)相关推荐

  1. 【数据结构】史上最好理解的红黑树讲解,让你彻底搞懂红黑树

    目录 一.红黑树简介 二.为什么需要红黑树? 三.红黑树的特性 四.红黑树的效率 4.1 红黑树效率 4.2 红黑树和AVL树的比较 五.红黑树的等价变换 六.红黑树的操作 6.1 旋转操作 6.2 ...

  2. 深度梳理:史上最全 Python 字符串格式化讲解

    大家好,今天给大家分享一篇堪称史上最全对字符串格式化的文章.喜欢点赞.收藏.关注. 上个周末看到"pandas数据格式化处理"的时候,想着把(设置小数位数,设置百分位,设置千位分隔 ...

  3. 人脸识别:史上最详细人脸识别adaface讲解-ckpt转onnx模型--第三节

    这章节我会讲解的是我在工作上的项目,人脸识别adaface,以下的讲解为个人的看法,若有地方说错的我会第一时间纠正,如果觉得博主讲解的还可以的话点个赞,就是对我最大的鼓励~ 上一章节我们讲到了模型的训 ...

  4. python的unicode编码_python unicode编码

    遇到编码问题,查阅了一些资料,有了一些理解,简单记录下. 首先,Unicode有个通用字符集 其次,每个字符有个编号(编码,即code points),规范为U+hhhh,其中每个h代表一个十六进制数 ...

  5. 史上最全的集合框架讲解 ----- Java 集合框架(3)---- Map 相关类最全解析

    引言 好了,步入正题,上篇文章Java 集合框架(2)---- List 相关类解析中我们一起看了一下 List 接口的相关具体类(ArrayList.LinkedList-.),这篇开始我们开始探索 ...

  6. C语言指针,这可能是史上最干最全的讲解啦(附代码)!!!

    点击上方"大鱼机器人",选择"置顶/星标公众号" 福利干货,第一时间送达! 指针对于C来说太重要.然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计 ...

  7. c语言贪吃蛇最简单代码_C语言指针,这可能是史上最干最全的讲解啦(附代码)!!!...

    点击上方"大鱼机器人",选择"置顶/星标公众号"福利干货,第一时间送达!指针对于C来说太重要.然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计算机 ...

  8. 史上最清晰的红黑树讲解(上)(转自CarpenterLee,纯学习用)

    本文以Java TreeMap为例,从源代码层面,结合详细的图解,剥茧抽丝地讲解红黑树(Red-Black tree)的插入,删除以及由此产生的调整过程. 总体介绍 Java TreeMap实现了So ...

  9. 史上最清晰的红黑树讲解(上)

    本文github地址 本文以Java TreeMap为例,从源代码层面,结合详细的图解,剥茧抽丝地讲解红黑树(Red-Black tree)的插入,删除以及由此产生的调整过程. 总体介绍 Java T ...

最新文章

  1. ansys怎么合并体_亚马逊合并拆分变体实操(干货)-合并
  2. C语言 求sin(x)的近似值
  3. ORA-20000: ORU-10027: buffer overflow, limit of 2000 bytes
  4. 构建azure对话机器人_如何在5分钟内使用Azure创建聊天机器人
  5. pycharm运行pytorch版pix2pix学习笔记
  6. 在LINUX上部署SOFA
  7. 手部精细动作有哪些_3-6岁手部精细动作训练游戏!促进孩子大脑发育
  8. Windows XP优化设置之网络篇
  9. 经典剖析电源PCB布板与EMC的关系(上)
  10. 定积分分部积分典型例题_定积分证明题方法总结六篇
  11. html静态页面作业——品牌红酒销售网页模板(4页) html网页设计期末大作业_网页设计平时作业
  12. k8s中部署prometheus监控告警系统-prometheus系列文章第一篇
  13. F2FS源码分析-1.4 [F2FS 元数据布局部分] Segment Infomation Table-SIT结构
  14. 基于STM32的五子棋游戏
  15. geoserver制作离线地图
  16. 为什么我的同花顺选股服务器列表为空,同花顺选股公式,为什么我就选不出股票来呢数......
  17. IDEA右键新建时没有Java Class选项-解决办法
  18. P4848 崂山白花蛇草水
  19. 仁、义、礼、智、信、衷、孝、节、勇、和
  20. 【DIY】树莓派ROS智能小车

热门文章

  1. TP6.0 调试模式下关闭Trace调试
  2. SHTC3的研发经历
  3. React学习-event.preventDefault()方法的简单介绍
  4. Ubuntu 普通用户deb安装失败
  5. 电脑系统服务器事件日志不可用,windows10系统提示事件日志服务不可用如何解决...
  6. 电话号码生成英语单词 OpenJ_Bailian - 3712 (c++,打表)
  7. 我的创作纪念日【在分享中感受被需要的价值】
  8. weavenet简介
  9. [建站日记]3day 回到命令行界面
  10. 全国计算机技术与软件专业技术资格(水平)考试相关知识汇总