钾肥喵的窝

我在 CODING 部署的 Hexo 博客

0%

浅谈Java中的char | 拿前朝的Unicode表示本朝的字符?

char到底占几个字节?

两个 (65536个码位, 0 ~ 65535)

这个Unicode它保真吗?

2020-03-10 发布的 Unicode 13.0.0 包含 143,859 个字符.[1]

来做一道简单的比较大小: 143859 和 65536

那么 char 使用的 Unicode 保真吗?

答案是保真的, 接下来简单介绍一下 Unicode 相关知识

哈是Unicode

Unicode, 官方中文名称 统一码, 也被称为 万国码, 是一套通用字符集标准.

起源

国际标准化组织(ISO), 于1984年创建 ISO/IEC JTC1/SC2/WG2 工作组, 希望建立通用字符集(Universal Character Set, UCS), 并最终制定 ISO 10646 标准

统一码联盟, 由 Xerox, Apple 等软件商于1988年成立, 并开发了 Unicode标准(The Unicode Standard)

1991年前后, 两个项目的参与者都认识到, 世界不需要两个不兼容的字符集. 于是, 它们开始合并双方的工作成果, 并为创立一个单一编码表而协同工作. 1991年, 不包含CJK统一汉字集的Unicode 1.0发布. 随后, CJK统一汉字集的制定于1993年完成, 发布了ISO 10646-1:1993, 即Unicode 1.1.

从Unicode 2.0开始, Unicode采用了与ISO 10646-1相同的字库和字码;ISO也承诺, ISO 10646将不会替超出U+10FFFF的UCS-4编码赋值, 以使得两者保持一致. 两个项目仍都独立存在, 并独立地公布各自的标准. 但统一码联盟和ISO/IEC JTC1/SC2都同意保持两者标准的码表兼容, 并紧密地共同调整任何未来的扩展.

平面的概念

Unicode字符平面映射

随着字符数的增多, Unicode 原有的 16位 空间不够用了, 于是从 Unicode 3.1(2001-03 发布) 开始, 引入了平面(Plane)的概念, 设置了16个辅助平面. 原有的 Unicode 空间称为基本平面(Basic Multilingual Plane, BMP).

平面 始末字符值 中文名称 英文名称
0号平面 U+0000 - U+FFFF 基本多文种平面 Basic Multilingual Plane, BMP
1号平面 U+10000 - U+1FFFF 多文种补充平面 Supplementary Multilingual Plane, SMP
2号平面 U+20000 - U+2FFFF 表意文字补充平面 Supplementary Ideographic Plane, SIP
3号平面 U+30000 - U+3FFFF 表意文字第三平面 Tertiary Ideographic Plane, TIP
4号平面

13号平面
U+40000 - U+DFFFF (尚未使用)
14号平面 U+E0000 - U+EFFFF 特别用途补充平面 Supplementary Special-purpose Plane, SSP
15号平面 U+F0000 - U+FFFFF 保留作为私人使用区(A区) Private Use Area-A, PUA-A
16号平面 U+100000 - U+10FFFF 保留作为私人使用区(B区) Private Use Area-B, PUA-B

UCS-2 与 UTF-16

ISO 10646 中为 UCS 定义了一种 16位 的编码形式(即 UCS-2), 编码固定占用2个字节, 它包含65536个编码空间.

两个字节显示是不够用的, 于是 UTF-16 来了, 它是一种变长编码, 占用 2 或 4 个字节, 可以表示所有 Unicode 编码.

UTF-16可看成是UCS-2的父集. 在没有辅助平面字符 (surrogate code points) 前, UTF-16与UCS-2所指的是同一的意思. 但当引入辅助平面字符后, 就称为UTF-16了. 现在若有软件声称自己支持UCS-2编码, 那其实是暗指它不能支持在UTF-16中超过2字节的字集. 对于小于0x10000的UCS码, UTF-16编码就等于UCS码.

UTF-16对辅助平面字符的支持是通过一种编码变换实现的, 详见维基:

UTF-16描述

结论

Java 的上线时间是 1995 年, 此时尚未引入辅助平面, 因此 char 的内码使用的是 UCS-2 编码, 被限定成了 16位.

辅助平面在 2001 年 3 月才随着Unicode 3.1标准发布, 此时已经有上百万的Java程序在运行中, 为了兼容性, Java放弃了将 char 改为 32位 的想法, 转而在标准库中提供相应的方法.

Java Documentation - Unicode

Supplementary Characters in the Java Platform

如何处理增补字符

以下内容主要来自:

Java中unicode增补字符(辅助平面)相关用法简介

Java5.0 (2004-09-30 发布) 中引入了对增补字符的支持, API主要在Character和String类里.

Character and String APIs

下面用 “𬌗” 字举例.

𬌗
U + 2C317
Dec: 181015

温馨提示: emoji也是Unicode字符哦, 下面以 “😂” 举例

😂
U + 1F602
Dec: 128514

温馨提示: printf() 方法也支持增补字符. 示例如下(此处codePoint是int类型, 表示字符的编码值)

1
System.out.printf("%c", codePoint);