「 」这个字符在百度中相当于「浏览器」三个字,这是为什么?
13 个回答
你输入的三个字符分别是:
它们都不属于常用汉字所在的 Unicode 0 号平面(BMP),而是在 2 号辅助平面,这个平面里放的都是不常用的中日韩汉字,有几万个,所以常见字体不包含它们,所以只能用图片的形式展示它的字形。
这三个字组成字符串用 JavaScript 的 Unicode 转义形式表示是 \u{26D4F}\u{289C8}\u{25668}
,而百度的服务器在拿到这三个字后(经过浏览器 UTF8 百分号编码和服务器解码),不知有意还是无意,把码点里表示平面序号的 2 去掉,从而转换成了 BMP 里的常见汉字,也就是 \u{6D4F}\u{89C8}\u{5668}
,这三个字刚好就是“浏览器”
试验一下,看看 zhihu 能不能显示出来……
很遗憾,这里无法显示出来。
本来也想从编码上考虑的,不过 紫云飞 的回答已经说明了可能原因,我也不清楚服务器那边的情况,就不重复了。
不过,既然来了,不研究一下有点浪费时间。顺着这个思路再进行验证:
随便选一个U+2xxxx汉字,就会被 baidu 转换成U+xxxx?
按照上述假设,以下转换可能成立:
实际测试:
再来个转换:
结果也是可行的:
从 Unicode 的汉字区块范围来考虑:
常用的 中日韩统一表意文字 / CJK 位于 BMP(4E00~9FFF)
中日韩统一表意文字扩展B区 / CJK ExtB 位于 SIP(20000~2A6DF):
由于二者不是完全一 一对应(ExtB的汉字比常用的字数多),因此按照 baidu 的转换规则,可能存在以下的问题:
在CJK区块之前的一个字符(U+4DFF):
测试结果是不支持:
用常见的字符再测试一下CJK汉字以外的情况:
结果可以替换 英文字母:
看评论中提到的强制读取低16-bit,看来是比较可能的原因了。实际情况还比较复杂(可能和系统支持的字符有关),这里就不多测试了,有兴趣的话可以自己试验一下。
============================
王絮飞 建议要从历史的角度来看问题。
于是,又到了翻故纸堆的时刻。
上世纪80年代,ISO 成立了 ISO/IEC JTC1/SC2/WG2,对 ISO 646 标准进行升级——制定 ISO 10646,定义通用字符集(UCS, Universal Coded Character Set),用来包含已知语言的所有字符。
最初想使用16位来对UCS进行编码,据说因为无法兼容当时中国的汉字编码,因此扩充到了32位。
该工作组(ISO/IEC JTC1/SC2/WG2)现在仍然在运行之中:
(注意下图墙上的横幅文字)
1987年,施乐公司的 Joe Becker 与苹果公司的 Mark Davis 以及 Lee Collins 合作,启动了 Unicode 项目。三个程序员,顶个ISO……还不行。在那个386电脑都是高科技产品的年代,这几个人认为人们使用的文字之中,不同字符的数量不会超过 16384个( 2^{14} ),因此用16位进行编码,就完全足够了!结果 Unicode 就按16位编下去了。
16位 Unicode 的由来:
1991年,施乐和苹果等厂商觉得这个项目不错,就成立了 Unicode 联盟(The Unicode Consortium),继续对各种文字编码进行统一工作,进而形成标准。(有能力和 ISO 一起坐下来喝咖啡谈业务了)
后来 ISO 和 Unicode 发现双方在做着差不多的工作,于是在1991年决定互相兼容。也有说法是当时ISO想偷懒,把各国的汉字编码直接搬过来用,但遭到了反对。因为有 Unicode 这样一个好榜样,所以一些国家就建议 ISO 虚心学习,把各国的文字编码都仔细整理一下。因此,ISO 和 Unicode 共同成立了CJK-JRG,也就是后来的 IRG(The Ideographic Research Group),专门针对汉字编码问题进行研讨 ——上文照片即中国专家参加2019年 IRG 会议。
1992年,Unicode 1.0.1 加入了 CJK 字符(20902个,U+4E00~U+9FA5)—— 王絮飞 的回答中提到 第1版不支持中文,(大约8个月之后)Unicode 升级成 1.0.1版 补上了汉字。
1993年,ISO/IEC 10646.1-1993 标准发布。同年6月,Unicode 1.1 发布,与 ISO标准相对应。
该ISO标准中规定了 UCS 的总体结构、以及 UCS 的肆八位(32位)正则形式 UCS-4 和 UCS 的双八位(16位)BMP形式 UCS-2。
按照该规定,UCS的整个编码空间可达 2,147,483,648 个字符(0~0x7FFF FFFF),实际使用数量可能在 679,477,248 个左右(0~0x2880 0000)。
在上世纪末的一些 RFC 文件中也可以看到这个UCS-4的范围(0~0x7FFF FFFF)。
把上限 0x7FFF FFFF 从16进制换算为2进制:
显然,最高位0不计的话,实际使用31位。
用图形来表示 UCS 的编码空间:
从上图可以看到 组 的数量为 128个(Group 00~7F)。空间一共包含 32768 个(0~0x7FFF)平面,每个平面能容纳 65536 个(0~0xFFFF)字符。
3万多个平面,数以亿计的字符码位!(如果想起了上文 ISO 直接照搬各个国家编码 的说法,这3万个平面的用途就显而易见了。)ISO 果然高瞻远瞩——可得广厦亿万间!不过,电脑厂商们要考虑实际情况。就在这个标准发布的1993年,Pentium 66MHz CPU 刚问世。Windows 3.1 还是16位!方正和金山、联想、巨人仍在卖汉卡……ISO 想给UCS造那么多的楼,建那么多房间,可是造楼成本太高,入住率又太低。于是一帮开发商最终让128组缩水到1组都不满,3万多个平面改成了十几个——ISO只好降低了标准。
从 Unicode 13 的介绍来看,2020年收集的字符还不到15万个。ISO在1993年就给出上亿字符的空间,步子确实太大了!
1996年7月,Unicode 2.0 发布。ISO/IEC 10646.1-1993 标准也进行了修订。
慢慢地,UCS 的空间上限就变成了 0x10 FFFF。
原先的 Group 00,有256个平面(Plane 00~FF)。包括1个基本多文种平面(BMP,Plane 00)、223个辅助平面(Plane 01~DF),以及 32个专用平面(Plane E0~FF) 。
上限降到 0x10 FFFF 之后,就只有17个平面了(0~0x10)。包括1个基本多文种平面(BMP,Plane 00)、16个辅助平面(Plane 01~10),每个平面容纳 65536 个(0~0xFFFF)字符。
精简之后的编码空间理论上可容纳 1,114,112 个字符(0~0x10 FFFF)。
RFC文件中同样可以看到这个变化:
再把上限 0x10 FFFF 从16进制改为2进制:
显然,只用了 21位——之前 王絮飞 的答案中也提到 好像是实际只需要21位。
好累!写得有点多了。考古工作暂时告一段落,后续 UTF-8 等内容,下次再提吧……