从0开始构建自己的前端知识体系-有趣的unicode

前言

最近在做表单需求的时候遇到了emoji的问题,发现自己对字符编码上的理解还是过于浅显,于是翻阅资料,弥补缺陷。

What is unicode

简单来讲,unicode就是一个机器语音与人类语言的一张对应表。

可以理解为一个很大很大的map,唯一的key对应唯一的字符。

  • 重要理念

    • 码点

      码点指的是unicode这个map里的每一个key

      例如\u004a对应的是J这个字符,那么J的码点就是74

    • unicode与编码

      编码是对码点进行的编排,我们日常说的UTF-8, UTF-16, UTF-32都是编码方式。不同的编排方式有不同的优势与作用。

    • 码点范围

      • 基础平面

        码点从0x0000 - 0xFFFF,共可存放65536个字符

      • 辅助平面

        码点从0x010000 - 0x10FFFF,共可存放16 * 65536个字符,可以划分为16个不同的平面

故我们可以认为目前unicode码表的码点最多可以用4个字节来表示
  • history

    Ascii码大家都了解,128个字符,1个字节完全可以一一对应。但是计算机不是光美国使用,全世界人民都想用计算机,都想在计算机上显示出自己的语言。于是就对这1个字节的剩余128个空间开始搞事情。

    那么问题来了,中国文化博大精深,128个空间对于中国文字来讲,简直不够塞牙缝。于是国人自己搞了一套GBK码表用两个字节就能表示65536个字符了,暂时解决了一下问题。

    但是码表与编码不统一,必然会导致两个计算机解码显示上的差异,也就造成了所谓的乱码。

    于是unicode的目的,就是为了建立一张能容纳全人类各种文化的字符的码表,来统一互联网的字符规范。

unicode 编码规则

通过编码规则可以对字符进行传输,通过解码后的码点与unicode表对照可以正确的显示文字

  • UTF-32

    一种很简单的定长编码方式,均为4个字节编码

    • 优点

      查找复杂度为O(1)

    • 缺点

      浪费空间,传输内容只有ASCII时会是其的4倍。

故在网络传输中,传输内容的大小决定了流量与客户体验,这种编码方式并不适合互联网。

  • UTF-16

    一种变长的编码方式,采用2个字节来表示基础平面,4个字节来表示辅助平面

    编码范围字节
    0x0000 - 0xFFFF2
    0x010000 - 0x10FFFF4
    • question

      那么在编码与解码过程中,是如何区分应该是2字节还是4字节呢?

    • answer

      我们知道,辅助平面的字符共有 16 * 65536个,也就是 2^20个。

      在基本平面内,码点从0xD800到0xDFFF是一个空段,不对应任何字符。那么正好从0xD800-0xDBFF空间大小为1024(2^10),从0xDBFF-0xDFFF空间大小为1024(2^10)。于是就可以把辅助平面的码点分为高低位映射在这两个码点范围内,正好可以存储所有的辅助平面字符。

      也就是说只要超过0xFFFF的码点,都会被编码成高位在0xD800-0xDBFF,低位在0xDC00-0xDFFF的4字节码点。这样解码的时候还是依次读取2字节,遇到0xD800-0xDBFF就知道这是个辅助平面字符,再读取2字节去解码

    • 转码公式

      1. 如果是基本平面字符,直接将码点转为对应的16进制形式,长度为2字节
      2. 如果是辅助平面字符,则使用转码公式
      H = Math.floor((c-0x10000) / 0x400)+0xD800
      
      L = (c - 0x10000) % 0x400 + 0xDC00
  • UTF-8

    一种变长的编码方式,越常用的字符编码长度越短

    • question

      如何区分到底应该读取几个字节来编码解码呢?

    • answer

      编码范围编码方式字节
      0x0000 - 0x007F0xxxxxxx1
      0x0080 - 0x07FF110xxxxx 10xxxxxx2
      0x0800 - 0xFFFF1110xxxx 10xxxxxx 10xxxxxx3
      0x010000 - 0x10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx4

      编码规则:

      1. 对于码点在0-127的,用1字节,第一位置0,后面按码点对应,其实就与ASCII相同了
      2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
由于UTF-8编码这种变长的编码规定,极大地节省了网络传输数据的空间,传输常用的ASCII码不用占据额外的空间,提升了效率

JavaScript编码规则

有趣的是,js与采用的是UCS-2编码方法。

UCS-2UTF-16编码的子集,只支持2字节解析,从而就导致了4字节字符被当做2个2字节字符解析,字符函数等就会出现问题。

  • question

    // '

相关推荐