字符集详解

80467305 2019-11-04

字符集相关的概念

字符集&编码

  • charset 是 character set 的简写,即字符集。
  • encoding 是 charset encoding 的简写,即字符集编码,简称编码。

编号 编码

  • 字符 <–> 编号 <–> 编码
  • 编号不涉及具体使用多少字节来表示、是用定长还是变长方案等细节问题。编号仅仅是一个抽象的概念,将具体字符映射到一个唯一的code上,是把字符数字化的一个过程。
  • 字符集是一组映射关系[字符 - 编号] ,即对字符的数字化抽象,但不体现具体的编码转换格式。如Unicode就是一个字符集。
  • 编码是编号的具体存储方式,将抽象的编号转化成具体的编码 - 编码对应[存储字节数、是否变长...]

下面具体以将Unicode展开讲解


Unicode字符集

  • Unicode 是 Unicode Standard(Unicode标准)的简写,所以 Unicode 即是指 Unicode 标准。
  • 它脱离具体平台、语言,给每一个字符 一个唯一的数字 -- 码点(code point)
  • 码点的格式 U+[XX]XXXX X:代表一个十六制数字 可以有 4-6 位,不足 4 位前补 0 补足 4 位,超过则按是几位就是几位。具体示例:

    • U+0048(不足 4 位前补 0 )
    • U+4F60
    • U+1D11E(超过4位则按实际位数)
  • 范围[U+0000,U+10FFFF] 理论大小为 10FFFF+1=110000(16进制) 是一个百万级别的数。

    10FFFF + 1 = 110000(16) = (16 + 1) * FFFF = 17 * 16^4 = 17 * 65536(10)
    
    可以拆分出 17 个 范围为FFFF的平面
  • 平面[Plane]为了更好分类管理如此庞大的码点数,把每 65536 个码点作为一个平面,总共 17 个平面。

    • 第一个平面称为 BMP(Basic Multilingual Plane 基本多语言平面),也叫 Plane 0,它的码点范围是 U+0000 ~ U+FFFF
    • 后续的 16 个平面称为 SP(Supplementary Planes)。范围超过了 U+FFFF 即超过了 2个byte = 16 bit (2^16)个的理论上限
    • CJK 统一汉字(CJK:Chinese, Japanese, and Korean,中日韩)在first plane 中间很大一片区域

      流传配置汉字的正则表达式 [\u4E00-\u9FA5] 就是plane 0 中这个范围的 Unicode值,严格来说是不准确的。
    • 代理区 BMP中还有一片空白,这段空白从 D8~DF。其中前面 D800–DBFF 属于高代理区(High Surrogate Area),后面的 DC00–DFFF 属于低代理区(Low Surrogate Area),各自的大小均为 4×256 (2^8) = 1024
      这两个区组成一个二维的表格,共有1024×1024=210×210=24×216=16×65536,所以它恰好可以表示增补的 16 个平面中的所有字符。

      高代理称为Lead,低代理位Trail,一高一低即是一个代理对
      映射关系,有图表示
      例如:
      (D8 00 DC 00)—>U+10000,左上角,第一个增补字符
      
      (DB FF DF FF)—>U+10FFFF,右下角,最后一个增补字符

Unicode的具体编码格式

三种编码方案的定变长与字节数总结:

  • UTF-8 :变长,1-4 字节;
  • UTF-16:变长,2 或 4 字节;
  • UTF-32:定长,4 字节。

定长与变长

  • 在容量 和 效率之间全行,出现了变长的编码方案。
  • 变长的设计核心在于区分不同的变长字节:利用高位区分,利用代理区区分
  • 默认标示位(高位来区分)的变长方案,损失了很多有效码位
  • 代理区做区分的方案(保留一部分code【70-80】排列组合,映射出70*80 100个code)

具体编码实现

UTF 即是 Unicode 转换格式(Unicode (or UCS) Transformation Format)

  • UTF-32

    • 码点最大的 10FFFF 占 21 位,UTF-32 采用的定长4 byte 则是 32 位。高位补 0 的形式补够 32 位即可,缺点占用空间太大。
    • 4字节 XXXX XXXX , XXXX XXXX , XXXX XXXX , XXXX XXXX
  • UTF-8

    • 变长的编码方案:1,2,3,4 四种 byte 组合
    • 采用高位保留方式 来区别不同变长

      • 1字节 0XXX XXXX (7)
      • 2字节 110X XXXX 10XX XXXX ) (11)
      • 3字节 1110 XXXX 10XX XXXX 10XX XXXX (16)
      • 4字节 1111 0XXX 10XX XXXX 10XX XXXX 10XX XXXX (21)
    • 码点对应字节

      1. 编码转二进制数,去掉高位0 判断采用几字节
      2. 一字节 有效位7位(2^7 = 128)兼容ASCII,[码点] U+0000 ~ U+007F (0~127)
      3. 二字节 11位有效,2^11 = 2048 个编码空间 码点 U+0080 ~ U+07FF (128~2047)

        • 因为去掉了一字节的码点,二直接码点从 128~2047,所以不会占满 2048 个编码空间,是有冗余的,下面同样如此
      4. 三字节 16位有效,65536 个编码空间 码点U+0800~U+FFFF (2048~65535)

        • 同样三字节码点范围 U+0800~U+FFFF(2048~65535)
        • 存着绝大部分汉字(常用字),还有很多偏门汉字保存在增补平面中
      5. 四字节剩余 21位有效位数,最大的Unicode码点 10FFFF(1 + 4 * 5) 也是 21 位,刚好囊括。U+FFFF 以上的增补平面的字符都在这里表示
      • 按照 UTF-8 的模式,它还可以扩展到 5 字节,乃至 6 字节变长,但 Unicode 说了码点就到 10FFFF,不扩充了,所以 UTF-8 最多到四字节就足够了
    • 码点转换为UTF-8编码

      1. 将码点转换成 2进制
      2. 将二进制数 按照UTF-8 固定位分组
      3. 选中几字节模式后,高位不足 补0
      4. 重新将 2进制数 转换成16进制数

        汉字“你” (U+ 4F60)
        
        转2进制  :U+ 4F60 -> 0100 1111 0110 0000  (16位 按照3字节转换)
        分组     :0100 1111 0110 0000 -> 0100 1111,01 10,0000 (3字节 4+6+6)
        替换有效位:1110 0100 1011 1101 1010 0000
        按字节转16进制:E4 BD A0
      • UTF-8 三字节模式固定了 1110 的开头模式,所以多数汉字总是以 1110 开头,换成 16 进制形式,1110 就是字母 E。
        如果看到一串的 16 进制有如下的形式:EX XX XX EX XX XX…每三个三个字节前面都是 E 打头,那么它很可能就是一串汉字的 UTF-8 编码了
  • UTF-16

    • BMP中的码点,直接对应无需转换 (plane 0 范围2byte = 16bit,16位刚好对应)
    • 变长的 2 或 4 字节编码模式

      • BMP内的字符使用 2 字节编码
      • 其它的则使用 4 字节组成所谓的代理对来编码
    • 代理区

      • 鸟瞰图中,一片空白的区域,就是代理区(Surrogate Area),
      • 为了编码增补平面中的字符而保留的,总共有 2048 个位置,均分为高代理区(D800–DBFF)和低代理区(DC00–DFFF)两部分,各1024,这两个区组成一个 二维的表格,共有:1024 × 1024 = 2^10×2^10 = 2^4×2^16 = 16×65536
      • 它恰好可以表示增补的 16 个平面中的所有字符
    • 码点转换

      • BMP 中直接对应,无须做任何转换
      • 增补平面 SP 中:

        1. 减去10000(16进制)[第一个平面中的所有码点]
        2. 除以代理区的行宽[ 1024(10进制) ] 商:第几个高代理区 余数:第几个低代理区
        3. Lead = (码点 – 10000(16)) ÷ 40016 + D800
          Trail = (码点 – 10000(16) % 40016 + DC00
      • 实际转换用API, 通过位移运算更高效

相关推荐