字符集和编码格式的简单学习
背景
因为遇到了一个数据库乱码的问题,
所以想着能够学习和总结一下字符集和编码格式相关的内容
内容可能比较宏大, 我这边能够写的可能不是很多.
希望是一个完善和提高自己的机会
学习的资料
https://deerchao.cn/blog/posts/unicode.html
大佬的文档很牛B. 看完之后豁然开朗了很多
https://zhuanlan.zhihu.com/p/461741666
知乎上面的一个内容
感觉写的比较全了, 各种编码格式相关
https://www.unicode.org/history/publicationdates.html
unicode的官方发布历史
关于字符集的来源
最开始的电脑从ENIAC开始, 其实他的输入和输出是打孔机类似的工具
那个时候只有数字和英文字符, 并没有字符显示的机会.
从70年代个人PC以及鼠标显示器的出现. 以及国际化, 各个国家都开始电算化之后
五花八门的字符展示就开始了
最开始应该都是商业公司开始在做, 比如微软和Oracle以及IBM
他们会有很多的不同的说法, 比如微软的代码页, 微软SQLServer的排序规则
Oracle的字符集, IBM的i18n的一些玩法.
unicode基金会
(1) 国际标准化组织(ISO),他们于1984年创建ISO/IEC JTC1/SC2/WG2工作组,
试图制定一份“通用字符集”(Universal Character Set,简称UCS),并最终制定了ISO 10646标准。
(2) 统一码联盟,他们由Xerox、Apple等软件制造商于1988年组成,并且开发了Unicode标准
(The Unicode Standard,这个前缀Uni很牛逼哦---Unique, Universal, and Uniform)。
1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。
于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。
从Unicode 2.0开始,Unicode采用了与ISO 10646-1相同的字库和字码;
ISO也承诺,ISO 10646将不会替超出U+10FFFF的UCS-4编码赋值,以使得两者保持一致。
两个项目仍都独立存在,并独立地公布各自的标准。不过由于Unicode这一名字比较好记,因而它使用更为广泛。
Unicode编码点分为17个平面(plane),
每个平面包含2的16次方(即65536)个码位(code point)。
17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从00到10,共计17个平面。
unicode的发布历史
unicode 1.0 1991 年发布的
最初的几个版本, 基本上 3-5年发布一个
2.0 1996年
3.0 1999年
4.0 2003年
5.0 2006年
6.0 2010年
7.0 2014年
但是从 7.0 开始 及本上每年一个 大版本, 基本上
到了 2023年已经发布了
15.0 2023年.
各个软件的兼容性的选择
字符存储不仅仅要考虑是否浪费磁盘空间和网络带宽
还要考虑字符串算法的性能问题.
最开始的操作系统, Windows 程序开发语言, java, javascript, 都是采用的 UCS-2 编码格式
但是需要说明
最开始的UCS-2 其实是一个定长编码格式. 2个字节表示所有的字符. 能够展示 65536个字符
定长编码有非常大的优势, 尤其是在进行字符串处理时.
不需要对每个字符取出来进行判断他的长度, 会极大的提高效率
这也是 UTF-8虽然可以最大化的节约磁盘和带宽,但是操作系统,数据库,编程语言并不会将他作为第一选择.
但是随着unicode的发展, 65536 已经明显不够使用,
此时unicode就开始使用其他的 16个panel 进行存储.
UCS-2不得已必须使用 变长字符编码, 这一个就与UTF-16保持一致起来.
他的特点是:
从0xD800-0xDFFF 这个区域外, 其他的表示unicode码.
这个区域有分为: 0xD800–0xDBFF (高代理区域)、0xDC00–0xDFFF (低代理区域)
基本上可以理解为 遇到 D8 到DF开头的编码, unicode 会自动的寻找下面一个双字节进行合并展示UTF-16的编码信息
虽然UTF-16 变成了变长编码 但是BMP里面的 65536-2048个字符表示 足够大部分情况下的使用, 性能依旧是最优解
关于mysql以及linux的兼容选择
Linux因为也是1991年发布的, 最开始没有考虑国际化, 所以他很侥幸的避免了UCS-2的历史坑.
所以一开始就兼容UTF-8 没有历史包袱, 非常开心
MySQL 自作聪明, 使用了 UTF8 又自作聪明的使用了UTF8MB3 导致这个字符集
不仅仅是变成编码, 性能贼垃圾, 还只能保存 65536个字符, 国际化一套糊涂.
所以感觉 MySQL虽然是最流行的开源数据库, 但是他的很多决策都是脑门被驴踢了的玩法.
另外根据大佬的解释:
MySQL 中排序规则应该使用 utf8mb4_unicode_ci,而不是 utf8mb4_general_ci。
后者性能稍微高于前者,但算法不符合 Unicode 标准,可能在处理某些语言文字时出现错误的结果。
utf8mb4_unicode_ci对应 Unicode v4.0,
较新版本的 MySQL 还同时支持 v5.2(utf8mb4_unicode_520_ci),v9.0(utf8mb4_0900_ai_ci)。
关于GB的几种字符集
常见的国标字符集有:
GB2312
GBK
GB18030
这里面除了GB18030之外都是双字节编码格式.
GB2312 1980 年发布, 共收录了 6763 个常用的汉字和字符
现在已经成为GBT2312 不再是强制标准
双字节编码.
GBK 于 1995 年发布 在 GB2312 的基础上添加了这部分字符,就形成了 GBK ,
全称 《汉字内码扩展规范》,共收录了两万多个汉字和字符,它完全兼容 GB2312
可以表示的汉字达到了20902个,另有984个汉语标点符号、部首等
注意GBK不是强制标准
GB18030
需要注意GB18030有至少三个版本了 2000,2005,2022
2000
字符集是中国政府在 2000 年发布的国家编码标准。
该标准设置的编码长度为一、二或四个字节。
GB18030-2000 包括 6763 个标准简体中文字符、13053 个繁体中文 (Big5) 字符、
3000 个在香港使用的字符以及 21003 个 GBK 字符
2005版本:
《信息技术 中文编码字符集》是以汉字为主并包含多种我国少数民族文字的超大型中文编码字符集,
其中收入汉字70000余个。在GB18030-2000的基础上增加了42711个汉字和多种我国少数民族文字的编码
(如藏、蒙古、傣、彝、朝鲜、维吾尔文等)。增加的这些内容是推荐性的,
原GB18030-2000中的内容是强制性的,市场上销售的产品必须符合。
故GB18030-2005为部分强制性标准,自发布之日起代替GB18030-2000。
《信息技术 中文编码字符集》
(GB 18030-2022)强制性国家标准发布,
将于2023年8月1日正式实施。新国标共收录汉字87887个,
比上一版增加录入了1.7万余个生僻汉字。
一个简单总结
数据库,操作系统,程序,浏览器,都涉及到字符集的问题.
虽然UTF-8的性能可能不是最优, 但是他应该是全链路范围内最优解
既可以实现国际化, 对各种各种的问题兼容忍耐程度也高
出问题也好找解决方案, 实在解决不了也情有可原.
国内来说GB18030-2000 是强制标准. 2023.8.1 已经发布了.
保证数据准确, 性能优秀其实是所有产品的追求.
浏览器的字符集改天继续学习和研究一下.
说明: unicode 其实是有 1个 BMP 的panel 和 16个SMP区域构成.
基本多文种平面(BMP)、辅助平面(SMP)和增补平面(SIP)
另外再BMP和第15和第十六个SMP里面有一定量的PUA区域 可以自行定义
Unicode规范中,私有使用区域一共3个,分别是1+2,
1是指在BMP(基本多语言平面)中的U+E000到U+F8FF,共6400个编码点位,
2是指两个补充私有区域,很大,其范围几乎覆盖了平面15和平面16的全部
(BMP是编号为0的平面,15、16是Unicode的最后两个平面,除了末尾的两个编码点,其余都是私有使用区域)
15号平面的私有使用区域范围是:U+F0000到U+FFFFD, 末尾的两个(U+FFFFE和U+FFFFF)除外;
16号平面的私有使用区域范围是:U+100000到U+10FFFD,末尾的两个(U+10FFFE和U+10FFFF)除外。