赞
踩
在计算机种中,1 字节对应 8 位二进制数,而每位二进制数有 0、1 两种状态,因此 1 字节可以组合出 256 种状态。如果这 256 中状态每一个都对应一个符号,就能通过 1 字节的数据表示 256 个字符。美国人于是就制定了一套编码(其实就是个字典),描述英语中的字符和这 8 位二进制数的对应关系,这被称为 ASCII 码。
ASCII 码一共定义了 128 个字符,例如大写的字母 A 是 65(这是十进制数,对应二进制是0100 0001)。这 128 个字符只使用了 8 位二进制数中的后面 7 位,最前面的一位统一规定为 0。
太极生两仪,两仪生四象,四象生八卦
英语用 128 个字符来编码完全是足够的,但是用来表示其他语言,128 个字符是远远不够的。于是,一些欧洲的国家就决定,将 ASCII 码中闲置的最高位利用起来,这样一来就能表示 256 个字符。但是,这里又有了一个问题,那就是不同的国家的字符集可能不同,就算它们都能用 256 个字符表示全,但是同一个码点(也就是 8 位二进制数)表示的字符可能可能不同。例如,144 在阿拉伯人的 ASCII 码中是 گ,而在俄罗斯的 ASCII 码中是 ђ。
因此,ASCII 码的问题在于尽管所有人都在 0 - 127 号字符上达成了一致,但对于 128 - 255 号字符上却有很多种不同的解释。与此同时,亚洲语言有更多的字符需要被存储,一个字节已经不够用了。于是,人们开始使用两个字节来存储字符。
各种各样的编码方式成了系统开发者的噩梦,因为他们想把软件卖到国外。于是,他们提出了一个“内码表”的概念,可以切换到相应语言的一个内码表,这样才能显示相应语言的字母。在这种情况下,如果使用多语种,那么就需要频繁的在内码表内进行切换。
Unicode 仅仅只是一个字符集,规定了符合对应的二进制代码,至于这个二进制代码如何存储则没有任何规定。它的想法很简单,就是为每个字符规定一个用来表示该字符的数字,仅此而已。
之前提到,Unicode 没有规定字符对应的二进制码如何存储。以汉字“汉”为例,它的 Unicode 码点是 0x6c49,对应的二进制数是 110110001001001,二进制数有 15 位,这也就说明了它至少需要 2 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节,甚至更多字节来表示了。
这就导致了一些问题,计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?这里我们可能会想到,那就取个最大的,假如 Unicode 中最大的字符用 4 字节就可以表示了,那么我们就将所有的字符都用 4 个字节来表示,不够的就往前面补 0。这样确实可以解决编码问题,但是却造成了空间的极大浪费,如果是一个英文文档,那文件大小就大出了 3 倍,这显然是无法接受的。
于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,虽然看似方便,但是却不如另外两种编码方式使用广泛。
UTF-8 是一个非常惊艳的编码方式,漂亮的实现了对 ASCII 码的向后兼容,以保证 Unicode 可以被大众接受。
UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。 标准的 UTF-8 字符集编码是可以用 1~4 个字节去编码21位字符,这几乎包含了是世界上所有能看见的语言了。 编码规则如下:
对于单个字节的字符,第一位设为 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 根据上面编码规则对照表,进行 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,就表示该字符占用多少个字节。
MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。
超集
定义:如果一个集合S2中的每一个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S1就是S2的一个超集,反过来,S2是S1的子集。 S1是S2的超集,若S1中一定有S2中没有的元素,则S1是S2的真超集,反过来S2是S1的真子集。
那上面说了既然utf8能够存下大部分中文汉字,那为什么还要使用utf8mb4呢? 原来mysql支持的 utf8 编码最大字符长度为 3 字节,如果遇到 4 字节的宽字符就会插入异常了。三个字节的 UTF-8 最大能编码的 Unicode 字符是 0xffff,也就是 Unicode 中的基本多文种平面(BMP)。也就是说,任何不在基本多文本平面的 Unicode字符,都无法使用 Mysql 的 utf8 字符集存储。包括 Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上),和很多不常用的汉字,以及任何新增的 Unicode 字符等等(utf8的缺点)。
排序规则:
utf8mb4_unicode_ci
基于用于通用排序和比较的官方Unicode规则,该规则可以在多种语言中进行准确排序。(ci:case insensitive 忽略大小写)
utf8mb4_general_ci
是一组简化的排序规则,旨在尽力而为,同时采取许多旨在提高速度的捷径。它不遵循Unicode规则,在某些情况下(例如,使用特定语言或字符时)会导致不希望的排序或比较。在现代服务器上,这种性能提升几乎可以忽略不计。它是在服务器仅占当今计算机CPU性能的一小部分的时候设计的。
utf8_bin (大小写敏感)
参考文档:
https://segmentfault.com/a/1190000015307793
https://www.cnblogs.com/exmyth/p/3616672.html
https://blog.csdn.net/weixin_42785557/article/details/83512138
https://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
https://www.cnblogs.com/crazylqy/p/10184291.html
https://baike.baidu.com/item/%E8%B6%85%E9%9B%86/1059571?fr=aladdin
…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。