详解Unicode和JavaScript字符编码

2023-10-28

Unicode

Unicode,又称万国码、统一码和国际码,是由统一码联盟制定的一套规范统一的字符编码集,其设计意图是将世界上所有字符都包含在其中,它使用特定的十六进制编号来表示字符,每一个特定十六进制编号统称为码点,也叫码位,用“U+”紧接四位或五位十六进制数字来进行表示(例如U+597D表示中文“好”),在Unicode3.0中,也可用“U-”紧接八位十六进制数字表示。目前,Unicode整理并编码了世界上绝大部分的字符,并且已经普遍运用到各个编程语言,其中就包括了接下来要讲的JavaScript编码。

Unicode的最新版本是2020年3月发布的13.0,其中共收录了143,924个符号。当前实际应用的统一码版本是使用16位二进制的编码空间,也就是每个字符占用两个字节,理论上最多可表示216(即65536)个字符,其范围是0 ~216-1,写成十六进制就是U+0000 ~ U+FFFF,这基本满足当前各语言的日常使用,要注意的是16位编码空间也并未完全用于字符编码,其中留有相当一部分作为特殊作用或者后续扩展,例如后面要说的 “ 辅助区间 ”,上述16位编码空间被称为 “ 基本平面 ”,但最新版本扩展定义了其余16个“辅助平面”,其码点范围是U+010000 ~ U+10FFFF,用于收录更多的字符,每个平面可编码字符数量理论上与基本平面一致,所以17个平面至少需要占据21位编码空间,可收录字符数量理论上为221个,略小于三个字节,但实际上却是使用四个字节来存储辅助平面的字符,其目的主要是便于未来版本的扩充以及和其它字符集进行融合。

上述为Unicode做了个详细介绍,但是本质上只说明了Unicode的编码方式,而在实际传输或者存储的过程中,可能由于系统或者平台的差异或者出于空间节省的目的,在实现的方式上有所不同。简而言之

Unicode就是一本用指定一组特定二进制序列表示字符的字符典籍,它只制定字符的对应二进制序列,但没说明该字符二进制序列要以何种方式进行传输或存储。

Unicoded的实现方式就是常讲的Unicode转换格式(Unicode Transformation Format,简称为UTF),常见的Unicode转换格式有UTF-8UTF-16UTF-32,当然还有其它,这里就暂不讲述,以下各自讲一下这三种转换格式的特点和转码方式。

UTF-8

UTF-8,英语全称是8-bit Unicode Transformation Format,是一种针对Unicode的可变长字符编码,也是当前使用率最高和应用最广泛的转码方式。因为Unicode较小码点的使用频率较高,如果直接使用Unicode编码则会效率低下,并浪费大量内存空间,而本身UTF-8就是为了解决向后兼容ASCII编码而设计的,Unicode的前128个字符的二进制编码与ASCII码一一对应,所以为了节省空间,提高编码效率,UTF-8根据自己制定的编码规则,使用一至四个字节对Unicode所有的有效码点进行编码。

关于Unicode转换为UTF-8的编码规则其实很好理解,只有两条

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

  • 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的二进制位

Unicode符号范围(十六进制) UTF-8编码方式(二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。

下面以汉字 “ 严 ” 为例,演示如何实现 UTF-8 编码。

严的 Unicode 是U+4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是0xE4B8A5。

同样,解码UTF-8二进制序列的过程也很简单。当拿到一串经UTF-8编码后的字节序列时,对于其中的任意字节,如果第一位是0,则表示该字节是单字节字符(ASCII码);如果第一位是1,第二位是0,则表示该字节是多字节字符中的一个字节(非ASCII码);如果前两位是1,第三位是0,则表示该字节是两个字节表示的字符中的第一个字节,则和与其紧接的下一个字节组成该字符的字节编码。后面三字节和四字节表示的字符的识别规则同理。

我们还是以汉字 “ 严 ” 为例,简单实现UTF-8解码。

首先,我们收到一串二进制序列11100100 10111000 10100101,也知道它的转换格式是UTF-8,开始识别第一个字节可以知道后面两个字节都是某个字符的组成字节,根据上面表格,第一个字节前四位,后两字节前两位都是标识位,所以不提取,只提取非标识位,得到二进制序列100 111000 100101,其十六进制为0x4E25,对照Unicode码点表,与之相同码点对应的字符正好是汉字“严”。

至此,UTF-8的介绍就到这里。

UTF-16

UTF-16,全称16 bits Unicode/UCS Transformation Format,是Unicode字符编码五层次模型的第三层,也就是字符编码表(Character Encoding Form,简称CEF,也称为"storage format")的一种实现方式,它将Unicode字符集的抽象码位映射为16位长的整数(即码元,指有限大小的数字,此处UTF-16的16指的就是码元为16位)的序列,简单的说就是将字符码点用一个或多个码元表示。而对于Unicode字符集来说,一个码元表示所有字符是远远不够的,所以超出一个码元表示范围的字符都是用两个码元组成来表示的,所以实质上UTF-16也是一种变长字符编码。这和UTF-8有很大的不同,UTF-16的最小表示单位是两字节,而UTF-8是一个字节,所以UTF-16是无法兼容ASCII。

上面说过,码点范围U+0000 ~ U+FFFF是Unicode的基本平面,并且在这个区间内并不是每个码点都映射字符,而是留有一部分区间另有它用。Unicode标准规定,从U+D800到U+DFFF之间的码位区段是永久保留不映射到Unicode字符,而这个区间则用于对辅助平面的字符的码位进行编码,这段区间叫做代理区间。

 

我们先简单说一下UTF-16的编码规则,基本平面和辅助平面的编码方式是不一样的。

  • U+0000 ~ U+FFFF码位区间

Unicode第一个平面,也就是基本平面,恰好是一个码元空间,所以在该区间中的字符编码成UTF-16时,其UTF-16编码就是该字符的Unicode码点编码。

  • U+010000 ~ U+10FFFF码位区间

Unicode辅助平面在UTF-16中被编码成一对16比特长的码元(32位,4字节),其被称为“代理对”。具体编码规则如下

辅助平面的十六进制区间范围为0x010000 ~ 0x10FFFF,分别减去0x10000,得到值的范围是0 ~ 0xFFFFF,所以可以知道辅助平面的码位有220(1,048,576)个,而要完整表示该区间每个值需要20个二进制位。

UTF-16将这20位拆成两半,前10位加上0xD800,映射在0xD800~0xDBFF(空间大小2^10),称为高位代理(high surrogate);后10位加上0xDC00,映射在0xDC00~0xDFFF(空间大小2^10),称为低位代理(low surrogate),但是实质上高位代理的值要小于低位代理的值,所以为了避免混淆,高位代理也称为前导代理,低位代理也称为后尾代理。

此后意味着,一个辅助平面的字符,可以被拆成两个基本平面的字符表示,并进行相应的传输和存储。

这里有个地方要了解一下。如果我们用两个16位长码元序列来表示辅助平面中的220个字符,则第一个码元(即前导代理)要容纳上述20位中的前10位,第二个码元(即后尾代理)要容纳上述20位中的后10位,可以知道前导代理和后尾代理所能表示的个数都为210,也就是1024,故需要在基本平面中保留2048个不映射任何Unicode字符的码位才能符合需求,这也刚好是U+D800~U+DFFF区间的大小。

补充一个码元所表示字符是否在基本平面的判定规则。当接收到一连串经UTF-16编码后的字节序列时,会先读取第一个码元,也就是前16位,假如不在代理区间内,那说明该码元对应的字符码位在基本平面内。假如第一个码元在代理区间内,则可以断定该字符码位在辅助平面中,接下来则判断该码元的值是在高位代理的值范围还是在低位代理的值范围之内,如果在高位代理的值范围之内,则表示该码元是表示某字符的码元序列中的前一个码元,则与之紧接的下一个码元也是表示该字符的码元序列中的后一个。

下面以码位U+10437(

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解Unicode和JavaScript字符编码 的相关文章

随机推荐

  • sshd无法启动

    sshd 无法开启 1 开启sshd systemctl start sshd 2 查看sshd状态 systemctl status sshd service 显示sshd服务开启失败 解决方法 1 输入 sshd t 进行检查 报错信息
  • 高等数学(工本)计算题、综合题

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
  • 智慧物流之RFID物流供应链仓库管理系统,智能化的仓库rfid管理-新导智能

    摘要 物流与供应链管理在企业的整个管理流程中起着非常重要的作用 如果不能保证及时准确的入库 出库 物流和库存控制等供应链管理 将会给企业带来巨大损失 这不仅表现为各项管理费用的增加 而且会导致客户服务质量难以得到保证 最终影响企业的市场竞争
  • python关于SSLError的解决方法

    最近在使用http client调用btcd时报错SSLError Btcd Thread
  • 信息收集 —— dmitry

    每天学习一个Kali工具 dmitry 1 是什么 DMitry是黑客渗透流程中进行深度信息收集的利器 它是一个由C语言编写的UNIX GNU Linux命令行工具 无GUI操作界面 需掌握其常用使用参数 2 干什么用 1 端口扫描 可探测
  • 大鹏展翅_ParparVM展翅高飞

    大鹏展翅 我们写了很多关于为iOS构建的新VM的体系结构以及构建它的原因 直到最近 我们一直将其视为一种Codename One专用工具 只会对我们有用的东西 我们之所以使用开放源代码 是因为 这就是我们的方式 此后没有多加考虑 最近 我们
  • Vscode 下pip的换源方式(包括临时换源和永久换源)

    换源方式 这里我们提供两种换源的方式 临时换源 永久换源 临时换源 临时换源只需要在pip安装包时 加上一个 i参数后接源的url即可 1 临时换源 复制代码 清华源 pip3 install markdown i https pypi t
  • 若依绕过登录页访问其他自定义页面,以及自定义公众号页面账号登录后权限获取

    1 添加白名单路由path路径 2 路由路径进行配置 component resolve gt require views wxgzh Login resolve 白名单 3 公众号登录时候需要保存后端返回的token值 自定义公众号登录后
  • Launcher与普通Activity的区别

    Launcher与普通Activity的区别 分类 Android应用 2013 09 05 15 40 692人阅读 评论 0 收藏 举报 activity launcher MONKEY HOME Intent 目录 1 Intent
  • Docker笔记(十三):容器日志采集实践

    日志是服务运行过程中的一个关键环节 借助日志 我们可以排查定位问题 也可以借助集中化的日志管理平台 如ELK 来做一些必要的数据统计分析 在Docker环境中 日志的采集比传统环境更为复杂 因此了解Docker日志的管理机制 及基于此熟悉日
  • 解决Visual Studio Code 热键冲突

    因为最近很火的ChatGPT 更新了VSCode的版本 但是界面和配置有了一些变化 原来的热键也有所调整 在使用markdown的时候 enter键竟然都出现了冲突 在此记录一下操作步骤 非常简单 报错如下 command markdown
  • Python如何使用和配置Anaconda入门

    1 Anaconda介绍 Anaconda 是一款广泛使用的Python和R语言开发环境 集成了许多常用的科学计算和数据分析库 它包括conda Python解释器以及大量有用的库和工具 使得您可以更轻松地搭建Python和R的开发环境 此
  • QTP11破解无期限使用

    1 找到C ProgramData SafeNet Sentinel目录 更名或者删除 2 找到QTP11安装目录下bin子目录 如C Program Files x86 HP QuickTest Professional bin 执行in
  • 服务器PCI插槽上的固态硬盘,SSD接口详解,再也不会买错固态硬盘了

    硬盘知识科普中 我们提到了SSD的发展史虽短 但是种类和协议比HDD不知道多到哪里去了 因此 本期小编就通过接口类型 总线标准和协议标准来详细地介绍SSD 本文可能会出现很多小白都没有见过或者听过的名词 但是 对科技的探索 就是在不断学习新
  • 分享97个社区论坛PHP源码,总有一款适合你

    社区论坛 PHP源码链接 https pan baidu com s 1G4mtEKq7jPCG74ArOUwhLQ 提取码 484u 分享97个社区论坛PHP源码 总有一款适合你 下面是文件的名字 我放了一些图片 文章里不是所有的图主要是
  • 【openeuler 21.3】Linux硬盘分区、更改/home目录挂载空间及root目录扩容

    简介 公司使用的服务器的硬盘用的是RAID阵列 装openeuler系统时总共划分了两个阵列组 因为系统目前只使用了一个硬盘阵列 现在打算将一个阵列用作系统盘 将系统默认分配给home目录的空间分配给 目录提升 目录空间 另一个阵列全数用作
  • XML 学习笔记(基础)

    XML文件不区分大小写
  • C# 窗体大小运行时已固定,但是运行和实际Form.CS的不一样

    在属性找到AutoSizeMode 改为GrowAndShrink即可
  • 数据结构与算法之二叉排序树的增加,删除,遍历

    顺序二叉树 子树的左节点小于子树节点 子树的右节点大于子树节点 和子树相同大小的节点可在左也可在右一般不提倡出现相同大小的节点 优点 数组遍历快而插入删除效率不高 链表插入删除效率高 而遍历效率不高 而二叉排序树在遍历和插入删除效率都较高
  • 详解Unicode和JavaScript字符编码

    Unicode Unicode 又称万国码 统一码和国际码 是由统一码联盟制定的一套规范统一的字符编码集 其设计意图是将世界上所有字符都包含在其中 它使用特定的十六进制编号来表示字符 每一个特定十六进制编号统称为码点 也叫码位 用 U 紧接