Unicode、UTF-8、UTF-16 终于懂了 - 知乎切换模式写文章登录/注册Unicode、UTF-8、UTF-16 终于懂了程序员十三计算机起源于美国,上个世纪,他们对英语字符与二进制位之间的关系做了统一规定,并制定了一套字符编码规则,这套编码规则被称为ASCII编码ASCII 编码一共定义了128个字符的编码规则,用七位二进制表示 ( 0x00 - 0x7F ), 这些字符组成的集合就叫做 ASCII 字符集随着计算机的普及,在不同的地区和国家又出现了很多字符编码,比如: 大陆的 GB2312、港台的 BIG5, 日本的 Shift JIS等等由于字符编码不同,计算机在不同国家之间的交流变得很困难,经常会出现乱码的问题,比如:对于同一个二进制数据,不同的编码会解析出不同的字符当互联网迅猛发展,地域限制打破之后,人们迫切的希望有一种统一的规则, 对所有国家和地区的字符进行编码,于是 Unicode 就出现了Unicode 简介Unicode 是国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换Unicode 字符集的编码范围是 0x0000 - 0x10FFFF , 可以容纳一百多万个字符, 每个字符都有一个独一无二的编码,也即每个字符都有一个二进制数值和它对应,这里的二进制数值也叫 码点 , 比如:汉字 "中" 的 码点是 0x4E2D, 大写字母 A 的码点是 0x41, 具体字符对应的 Unicode 编码可以查询 Unicode字符编码表字符集和字符编码字符集是很多个字符的集合,例如 GB2312 是简体中文的字符集,它收录了六千多个常用的简体汉字及一些符号,数字,拼音等字符字符编码是 字符集的一种实现方式,把字符集中的字符映射为特定的字节或字节序列,它是一种规则比如:Unicode 只是字符集,UTF-8、UTF-16、UTF-32 才是真正的字符编码规则Unicode 字符存储Unicode 是一个符号集, 它只规定了每个符号的二进制值,但是符号具体如何存储它并没有规定前面提到, Unicode 字符集的编码范围是 0x0000 - 0x10FFFF,因此需要 1 到 3 个字节来表示那么,对于三个字节的 Unicode字符,计算机怎么知道它表示的是一个字符而不是三个字符呢 ?如果所有字符都用三个字节表示,那么对于那些一个字节就能表示的字符来说,有两个字节是无意义的,对于存储来说,这是极大的浪费,假如 , 一个普通的文本, 大部分字符都只需一个字节就能表示,现在如果需要三个字节才能表示,文本的大小会大出三倍左右因此,Unicode 出现了多种存储方式,常见的有 UTF-8、UTF-16、UTF-32,它们分别用不同的二进制格式来表示 Unicode 字符UTF-8、UTF-16、UTF-32 中的 "UTF" 是 "Unicode Transformation Format" 的缩写,意思是"Unicode 转换格式",后面的数 字表明至少使用多少个比特位来存储字符, 比如:UTF-8 最少需要8个比特位也就是一个字节来存储,对应的, UTF-16 和 UTF-32 分别需要最少 2 个字节 和 4 个字节来存储UTF-8 编码UTF-8: 是一种变长字符编码,被定义为将码点编码为 1 至 4 个字节,具体取决于码点数值中有效二进制位的数量UTF-8 的编码规则:对于单字节的符号,字节的第一位设为 0,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的, 所以 UTF-8 能兼容 ASCII 编码,这也是互联网普遍采用 UTF-8 的原因之一对于 n 字节的符号( n > 1),第一个字节的前 n 位都设为 1,第 n + 1 位设为 0,后面字节的前两位一律设为 10 。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码下表是Unicode编码对应UTF-8需要的字节数量以及编码格式Unicode编码范围(16进制)UTF-8编码方式(二进制)表格中第一列是Unicode编码的范围,第二列是对应UTF-8编码方式,其中红色的二进制 "1" 和 "0" 是固定的前缀, 字母 x 表示可用编码的二进制位根据上面表格,要解析 UTF-8 编码就很简单了,如果一个字节第一位是 0 ,则这个字节就是一个单独的字符,如果第一位是 1 ,则连续有多少个 1 ,就表示当前字符占用多少个字节下面以 "中" 字 为例来说明 UTF-8 的编码,具体的步骤如下图, 为了便于说明,图中左边加了 1,2,3,4 的步骤编号首先查询 "中" 字的 Unicode 码 0x4E2D, 转成二进制, 总共有 16 个二进制位, 具体如上图 步骤1 所示通过前面的 Unicode 编码和 UTF-8 编码的表格知道,Unicode 码 0x4E2D 对应 000800 - 00FFFF 的范围,所以, "中" 字的 UTF-8 编码 需要 3 个字节,即格式是 1110xxxx 10xxxxxx 10xxxxxx然后从 "中" 字的最后一个二进制位开始,按照从后向前的顺序依次填入格式中的 x 字符,多出的二进制补为 0, 具体如上图 步骤2、步骤3 所示于是,就得到了 "中" 的 UTF-8 编码是 11100100 10111000 10101101, 转换成十六进制就是 0xE4B8AD, 具体如上图 步骤4 所示UTF-16 编码UTF-16 也是一种变长字符编码, 这种编码方式比较特殊, 它将字符编码成 2 字节 或者 4 字节具体的编码规则如下:对于 Unicode 码小于 0x10000 的字符, 使用 2 个字节存储,并且是直接存储 Unicode 码,不用进行编码转换对于 Unicode 码在 0x10000 和 0x10FFFF 之间的字符,使用 4 个字节存储,这 4 个字节分成前后两部分,每个部分各两个字节,其中,前面两个字节的前 6 位二进制固定为 110110,后面两个字节的前 6 位二进制固定为 110111, 前后部分各剩余 10 位二进制表示符号的 Unicode 码 减去 0x10000 的结果大于 0x10FFFF 的 Unicode 码无法用 UTF-16 编码下表是Unicode编码对应UTF-16编码格式Unicode编码范围(16进制)具体Unicode码(二进制)UTF-16编码方式(二进制)字节表格中第一列是Unicode编码的范围,第二列是 具体Unicode码的二进制 ( 第二行的第二列表示的是 Unicode 码 减去 0x10000 后的二进制 ) , 第三列是对应UTF-16编码方式,其中红色的二进制 "1" 和 "0" 是固定的前缀, 字母 x 和 y 表示可用编码的二进制位, 第四列表示 编码占用的字节数前面提到过,"中" 字的 Unicode 码是 4E2D, 它小于 0x10000,根据表格可知,它的 UTF-16 编码占两个字节,并且和 Unicode 码相同,所以 "中" 字的 UTF-16 编码为 4E2D我从 Unicode字符表网站 找了一个老的南阿拉伯字母, 它的 Unicode 码是: 0x10A6F , 可以访问 https://unicode-table.com/cn/10A6F/ 查看字符的说明, Unicode 码对应的字符如下图所示下面以这个 老的南阿拉伯字母的 Unicode 码 0x10A6F 为例来说明 UTF-16 4 字节的编码,具体步骤如下,为了便于说明,图中左边加了 1,2,3,4 、5的步骤编号首先把 Unicode 码 0x10A6F 转成二进制, 对应上图的 步骤 1然后把 Unicode 码 0x10A6F 减去 0x10000, 结果为 0xA6F 并把这个值转成二进制 00 00000010 10 01101111,对应上图的 步骤 2然后 从二进制 00 00000010 10 01101111 的最后一个二进制为开始,按照从后向前的顺序依次填入格式中的 x 和 y 字符,多出的二进制补为 0, 对应上图的 步骤 3、 步骤 4于是,就计算出了 Unicode 码 0x10A6F 的 UTF-16 编码是 11011000 00000010 11011110 01101111 , 转换成十六进制就是 0xD802DE6F, 对应上图的 步骤 5UTF-32 编码UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 码即可,不需要任何编码转换。虽然浪费了空间,但提高了效率。UTF-8、UTF-16、UTF-32 之间如何转换前面介绍过,UTF-8、UTF-16、UTF-32 是 Unicode 码表示成不同的二进制格式的编码规则,同样,通过这三种编码的二进制表示,也能获得对应的 Unicode 码,有了字符的 Unicode 码,按照上面介绍的 UTF-8、UTF-16、UTF-32 的编码方法 就能转换成任一种编码了UTF 字节序最小编码单元是多字节才会有字节序的问题存在,UTF-8 最小编码单元是一字节,所以 它是没有字节序的问题,UTF-16 最小编码单元是 2 个字节,在解析一个 UTF-16 字符之前,需要知道每个编码单元的字节序比如:前面提到过,"中" 字的 Unicode 码是 4E2D, "ⵎ" 字符的 Unicode 码是 2D4E, 当我们收到一个 UTF-16 字节流 4E2D 时,计算机如何识别它表示的是字符 "中" 还是 字符 "ⵎ" 呢 ?所以,对于多字节的编码单元,需要有一个标记显式的告诉计算机,按照什么样的顺序解析字符,也就是字节序,字节序分为 大端字节序 和 小端字节序小端字节序简写为 LE( Little-Endian ), 表示 低位字节在前,高位字节在后, 高位字节保存在内存的高地址端,而低位字节保存在内存的低地址端大端字节序简写为 BE( Big-Endian ), 表示 高位字节在前,低位字节在后,高位字节保存在内存的低地址端,低位字节保存在在内存的高地址端下面以 0x4E2D 为例来说明大端和小端,具体参见下图:数据是从高位字节到低位字节显示的,这也更符合人们阅读数据的习惯,而内存地址是从低地址向高地址增加所以,字符0x4E2D 数据的高位字节是 4E,低位字节是 2D按照大端字节序的高位字节保存内存低地址端的规则,4E 保存到低内存地址 0x10001 上,2D 则保存到高内存地址 0x10002 上对于小端字节序,则正好相反,数据的高位字节保存到内存的高地址端,低位字节保存到内存低地址端的,所以 4E 保存到高内存地址 0x10002 上,2D 则保存到低内存地址 0x10001 上BOMBOM 是 byte-order mark 的缩写,是 "字节序标记" 的意思, 它常被用来当做标识文件是以 UTF-8、UTF-16 或 UTF-32 编码的标记在 Unicode 编码中有一个叫做 "零宽度非换行空格" 的字符 ( ZERO WIDTH NO-BREAK SPACE ), 用字符 FEFF 来表示对于 UTF-16 ,如果接收到以 FEFF 开头的字节流, 就表明是大端字节序,如果接收到 FFFE, 就表明字节流 是小端字节序UTF-8 没有字节序问题,上述字符只是用来标识它是 UTF-8 文件,而不是用来说明字节顺序的。"零宽度非换行空格" 字符 的 UTF-8 编码是 EF BB BF, 所以如果接收到以 EF BB BF 开头的字节流,就知道这是UTF-8 文件下面的表格列出了不同 UTF 格式的固定文件头UTF编码固定文件头根据上面的 固定文件头,下面列出了 "中" 字在文件中的存储 ( 包含文件头 )编码固定文件头常见的字符编码的问题Redis 中文key的显示有时候我们需要向redis中写入含有中文的数据,然后在查看数据,但是会看到一些其他的字符,而不是我们写入的中文上图中,我们向redis 写入了一个 "中" 字,通过 get 命令查看的时候无法显示我们写入的 "中" 字这时候加一个 --raw 参数,重新启动 redis-cli 即可,也即 执行 redis-cli --raw 命令启动redis客户端,具体的如下图所示MySQL 中的 utf8 和 utf8mb4MySQL 中的 "utf8" 实际上不是真正的 UTF-8, "utf8" 只支持每个字符最多 3 个字节, 对于超过 3 个字节的字符就会出错, 而真正的 UTF-8 至少要支持 4 个字节MySQL 中的 "utf8mb4" 才是真正的 UTF-8下面以 test 表为例来说明, 表结构如下:mysql> show create table test\G
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`name` char(32) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)向 test 表分别插入 "中" 字 和 Unicode 码为 0x10A6F 的字符,这个字符需要从 https://unicode-table.com/cn/10A6F/ 直接复制到 MySQL 控制台上,手工输入会无效,具体的执行结果如下图:从上图可以看出,插入 "中" 字 成功,插入 0x10A6F 字符失败,错误提示无效的字符串,\xF0\X90\XA9\xAF 正是 0x10A6F 字符的 UTF-8 编码,占用 4 个字节, 因为 MySQL 的 utf8 编码最多只支持 3 个字节,所以插入会失败把 test 表的字符集改成 utf8mb4 , 排序规则 改成 utf8bm4_unicode_ci, 具体如下图所示:字符集和排序方式修改之后,再次插入 0x10A6F 字符, 结果是成功的,具体执行结果如下图所示上图中,set names utf8mb4 是为了测试方便,临时修改当前会话的字符集,以便保持和 服务器一致,实际解决这个问题需要修改 my.cnf 配置中 服务器和客户端的字符集小结本文从字符编码的历史介绍了 Unicode 出现的原因,接着介绍了 Unicode 字符集中 三种不同的编码方式: UTF-8、UTF-16、UTF-32 以及它们的的编码方法,紧接着介绍了 字节序、BOM ,最后讲到了字符集在 MySQL 和 Redis 应用中常见的问题以及解决方案 ,更多关于 Unicode 的介绍请参考 Unicode 的 RFC 文档码字不易,走过路过麻烦点个赞呗!发布于 2021-11-18 07:52赞同 34717 条评论分享喜欢收藏申请
一遍弄清楚Unicode和UTF-8 - 知乎切换模式写文章登录/注册一遍弄清楚Unicode和UTF-8ivan学而不思则罔什么是Unicode?Unicode,中文又称万国码、国际码,是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。 简单来说,就是一套囊括的世界上大部分国家的文字编码方式,使得全球的计算机在文字编码上能够拥有统一的标准。为什么会有Unicode? 计算机是在美国发明的,理所当然的使用的是英文字母,构成英语的不过就是26个拉丁字母加一些符号和数字,所以最初的电脑编码系统比较简单,也就是大家最熟悉的ASCII ((American Standard Code for Information Interchange)美国信息交换标准代码)。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符 。 128个字符,只需要1个字节就可以表示。存储很简单,效率也很高。但是随着世界发展,世界上使用计算机的人越来越多,就带来了一个问题,不是全世界人民都使用的拉丁字母,有些国家使用的字母里有许多是ASCII里没有的。 人总是会想办法的,为了可以在计算机保存他们的文字,他们决定采用127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128到255这一页的字符集被称扩展字符集。 但是在中国,这一套行不通,我们使用的文字系统汉字的数量又有上万个,我们需要建立自己的编码方式。中国人的解决方案是:小于127号的还是继续使用,并且用2个大于127的字节表示一个中文字符,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的 全角 字符,而原来在127号以下的那些就叫 半角 字符了。 这个汉案叫做 “GB2312“。 但是中文汉字的数量太多了,不够用,大家发现冷门生僻字和繁体字等等还是无法识别。于是就只是要求高字节大于127就认为是2字节的中文字符,这样结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。但是还有少数民族同胞也需要使用电脑,于是有扩展少数民族字符,这样GBK扩成了 GB18030,这样,一套能适配中国的字符编码就完善了。 中国不是个例,当时几乎每个不兼容ASCII的国家都搞了一套自己的字符编码,且只适用于自己国家,可以想象各国之间沟通时的混乱,不知道编码方式,你看到的就是一团乱码。所以,创立一套统一世界字符的编码是势在必行的。 ISO(国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:弃用所有的地区性编码方案,重新搞一个包括了地球上所有文化的字母和符号的编码!叫做”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 Unicode。Unicode开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用 两个字节 ,也就是16位来统一表示所有的字符,对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,所以这个方案对使用低8位就足够的编码系统的那些人来说,储存空间着实有点浪费,因为互联网大部分的内容都还是英文的。这里就要讲到UTF-8了。UTF什么是UTF? 首先,我想大家都明白,字符编码其实就是把每一个字符与一个二进制串对应起来,形成一个对应关系,一张对应表。你可以直接按照这张对应表把字符转成二进制存储起来,再在别的地方读取出来按照这张表翻译出内容。就比如ASCII码,你只需要读出一个字节,然后查表就知道这是什么字符了。Unicode同样可以如此,你只需要每次读两个字节,然后查表就可以了。这样的方式就有一个痛点,原本ASCII码中单子节就能表示的字符,比如0000 0001,你必须存0000 0000 0000 0001(有人问为啥不能只存0000 0001啊?答:那碰到一个字符对应的二进制前8位也是0000 0001,那计算机怎么决定?所以必须两个字节对于一个字符)而最常用的字符都是单子节的,浪费的存储空间是很大的。 其实我们可以发现,问题并不出在Unicode的编码上,因为它定义的只是字符对应的一个编号而已,6万个符号无论你怎么编,都一定要6万个数来对应不是吗?这时大家可以看看上面的ASCII表图片,可以看到每个字符前面都有个10进制的数字,这其实就是排个序挨个给每个字符编个号而已,具体你怎么存,那是你存储方式的问题,人家只规定来这个编号对应哪个字符。只不过直接按照编号对应二进制来存刚好最合适而已。 但是在Unicode这里,直接用编号对应的二进制来存就不太合适,浪费太多,所以问题其实出现在存取的方式上面。这里就可以引出UTF了。Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对 Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicod转换格式(Unicode Transformation Format,简称为UTF)。 UTF-8也就是UTF中的一种而已,你肯定也听过还有UTF-16,UTF-32什么的。到这里其实我已经讲清楚Unicode和UTF-8的区别了,但是具体搞清楚UTF-8是采用了什么样的存取方式,哦不,我们现在要改口叫实现方式,从而实现了存储空间的节省,就需要到另一篇详解UTF-8是如何设计的了。发布于 2020-08-23 15:04字符编码ASCIIUnicode(统一码)赞同 192 条评论分享喜欢收藏申请
计算机基础知识之Unicode-彻底弄懂 Unicode 编码-CSDN博客
计算机基础知识之Unicode-彻底弄懂 Unicode 编码
最新推荐文章于 2024-01-29 10:30:42 发布
Three_ST
最新推荐文章于 2024-01-29 10:30:42 发布
阅读量6.8k
收藏
71
点赞数
23
分类专栏:
计算机基础
数据结构
文章标签:
unicode
utf8
编码
原文链接:https://www.jianshu.com/p/9c9073e601d7
版权
数据结构
同时被 2 个专栏收录
72 篇文章
0 订阅
订阅专栏
计算机基础
48 篇文章
0 订阅
订阅专栏
彻底弄懂 Unicode 编码
前言
为什么要有编码?
大家需要明确的是在计算机里所有的数据都是字节的形式存储、处理的。我们需要这些字节来表示计算机里的信息。但是这些字节本身又是没有任何意义的,所以我们需要对这些字节赋予实际的意义。所以才会制定各种编码标准。
编码模型
首先需要明确的是存在两种编码模型
A:简单字符集
在这种编码模型里,一个字符集定义了这个字符集里包含什么字符,同时把每个字符如何对应成计算机里的比特也进行了定义。例如 ASCII,在 ASCII 里直接定义了 A -> 0100 0001。也就是 ASCII 直接完成了现代编码模型的前三步工作。
B:现代编码模型
在现代编码模型里要知道一个字符如何映射成计算机里比特,需要经过如下几个步骤:
知道一个系统需要支持哪些字符,这些字符的集合被称为字符表(Character repertoire)
给字符表里的抽象字符编上一个数字,也就是字符集合到一个整数集合的映射。这种映射称为编码字符集(CCS:Coded Character Set),unicode 是属于这一层的概念,跟计算机里的什么进制啊没有任何关系,它是完全数学的抽象的。
将 CCS 里字符对应的整数转换成有限长度的比特值,便于以后计算机使用一定长度的二进制形式表示该整数。这个对应关系被称为字符编码表(CEF:Character Encoding Form)UTF-8, UTF-16 都属于这层。
对于 CEF 得到的比特值具体如何在计算机中进行存储,传输。因为存在大端小端的问题,这就会跟具体的操作系统相关了。这种解决方案称为字符编码方案(CES:Character Encoding Scheme)。
平常我们所说的编码都在第三步的时候完成了,都没有涉及到 CES。所以 CES 并不在本文的讨论范围之内。
现在也许有人会想为什么要有现代的编码模型?为什么在现在的编码模型要拆分出这么多概念?直接像原始的编码模型直接都规定好所有的信息不行吗?这些问题在下文的编码发展史中都会有所阐述。
ASCII
我们知道在计算机中,所有的信息最终都表示为一个二进制的字符串,每一个二进制位有 0 和 1 两种状态,通过不同的排列组合,使用 0 和 1 就可以表示世界上所有的东西。
而 1 字节对应 8 位二进制数,每位二进制数有 0、1 两种状态,因此 1 字节可以组合出 256 种状态。如果这 256 中状态每一个都对应一个符号,就能通过 1 字节的数据表示 256 个字符。美国人于是就制定了一套编码(其实就是个字典),描述英语中的字符和这 8 位二进制数的对应关系,这被称为 ASCII 码。
ASCII 码一共定义了 128 个字符,包括英文字母 A-Z,a-z,数字 0-9,一些标点符号和控制符号等。这 128 个字符只使用了 8 位二进制数中的后面 7 位,最前面的一位统一规定为 0。
GB2312
英语用 128 个字符来编码完全是足够的,但是用来表示其他语言,128 个字符是远远不够的。于是,一些欧洲的国家就决定,将 ASCII 码中闲置的最高位利用起来,这样一来就能表示 256 个字符。但是,这里又有了一个问题,那就是不同的国家的字符集可能不同,就算它们都能用 256 个字符表示全,但是同一个码点(也就是 8 位二进制数)表示的字符可能可能不同。例如,144 在阿拉伯人的 ASCII 码中是 گ,而在俄罗斯的 ASCII 码中是 ђ。
因此,ASCII 码的问题在于尽管所有人都在 0 - 127 号字符上达成了一致,但对于 128 - 255 号字符上却有很多种不同的解释。与此同时,亚洲语言有更多的字符需要被存储,一个字节已经不够用了。
但是这难不倒智慧的中国人民,我们不客气地把那些 127 号之后的奇异符号们直接取消掉, 规定:
一个小于 127 的字符的意义与原来相同,但两个大于 127 的字符连在一起时,就表示一个汉字;
前面的一个字节(他称之为高字节)从 0xA1 用到 0xF7,后面一个字节(低字节)从 0xA1 到 0xFE;
这样我们就可以组合出大约 7000 多个简体汉字了。
在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的 全角字符。
而原来在 127 号以下的那些就叫 半角字符 了。
中国人民看到这样很不错,于是就把这种汉字方案叫做 GB2312。GB2312 是对 ASCII 的中文扩展。
GBK
但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。
后来还是不够用,于是干脆不再要求低字节一定是 127 号之后的内码,只要第一个字节是大于 127 就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近 20000 个新的汉字(包括繁体字)和符号。
GB18030 / DBCS
后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK 扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。
中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 DBCS。
Double Byte Charecter Set:双字节字符集。
在 DBCS 系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于 127 的,那么就认为一个双字节字符集里的字符出现了。
因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码。
Unicode
最终,美国人意识到他们应该提出一种标准方案来展示世界上所有语言中的所有字符,出于这个目的,Unicode 诞生了。
Unicode 源于一个很简单的想法:将全世界所有的字符包含在一个集合里,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码了。
它从 0 开始,为每个符号指定一个编号,这叫做”码点”(code point)。比如,码点 0 的符号就是 null(表示所有二进制位都是 0)。
U+0000 = null
上式中,U+表示紧跟在后面的十六进制数是 Unicode 的码点。
这么多符号,Unicode 不是一次性定义的,而是分区定义。每个区可以存放 65536 个(2^16)字符,称为一个平面(plane)。目前,一共有 17 个平面,也就是说,整个 Unicode 字符集的大小现在是 2^21。
最前面的 65536 个字符位,称为基本平面(缩写 BMP),它的码点范围是从 0 一直到 2^16-1,写成 16 进制就是从 U+0000 到 U+FFFF。所有最常见的字符都放在这个平面,这是 Unicode 最先定义和公布的一个平面。
剩下的字符都放在辅助平面(缩写 SMP),码点范围从 U+010000 一直到 U+10FFFF。
Unicode 只规定了每个字符的码点,到底用什么样的字节序表示这个码点,就涉及到编码方法。
Unicode 编码方案
之前提到,Unicode 没有规定字符对应的二进制码如何存储。以汉字“汉”为例,它的 Unicode 码点是 0x6c49,对应的二进制数是 110110001001001,二进制数有 15 位,这也就说明了它至少需要 2 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节,甚至更多字节来表示了。
这就导致了一些问题,计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?这里我们可能会想到,那就取个最大的,假如 Unicode 中最大的字符用 4 字节就可以表示了,那么我们就将所有的字符都用 4 个字节来表示,不够的就往前面补 0。这样确实可以解决编码问题,但是却造成了空间的极大浪费,如果是一个英文文档,那文件大小就大出了 3 倍,这显然是无法接受的。
于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,虽然看似方便,但是却不如另外两种编码方式使用广泛。
UTF-8
UTF-8 是一个非常惊艳的编码方式,漂亮的实现了对 ASCII 码的向后兼容,以保证 Unicode 可以被大众接受。
UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。编码规则如下:
对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。这意味着 ASCII 码那个年代的文档用 UTF-8 编码打开完全没有问题。
对于需要使用 N 个字节来表示的字符(N > 1),第一个字节的前 N 位都设为 1,第 N + 1 位设为 0,剩余的 N - 1 个字节的前两位都设位 10,剩下的二进制位则使用这个字符的 Unicode 码点来填充。
编码规则如下:
Unicode 十六进制码点范围UTF-8 二进制
0000 0000 - 0000 007F0xxxxxxx
0000 0080 - 0000 07FF110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
根据上面编码规则对照表,进行 UTF-8 编码和解码就简单多了。下面以汉字“汉”为利,具体说明如何进行 UTF-8 编码和解码。
“汉”的 Unicode 码点是 0x6c49(110 1100 0100 1001),通过上面的对照表可以发现,0x0000 6c49 位于第三行的范围,那么得出其格式为 1110xxxx 10xxxxxx 10xxxxxx。接着,从“汉”的二进制数最后一位开始,从后向前依次填充对应格式中的 x,多出的 x 用 0 补上。这样,就得到了“汉”的 UTF-8 编码为 11100110 10110001 10001001,转换成十六进制就是 0xE6 0xB7 0x89。
解码的过程也十分简单:如果一个字节的第一位是 0 ,则说明这个字节对应一个字符;如果一个字节的第一位 1,那么连续有多少个 1,就表示该字符占用多少个字节。
UTF-16
Windows 内核、Java、Objective-C (Foundation)、JavaScript 中都会将字符的基本单元定为两个字节的数据类型,也就是我们在 C / C++ 中遇到的 wchar_t 类型或 Java 中的 char 类型等等,这些类型占内存两个字节,因为 Unicode 中常用的字符都处于 0x0 - 0xFFFF 的范围之内,因此两个字节几乎可以覆盖大部分的常用字符。
UTF-16 编码介于 UTF-32 与 UTF-8 之间,同时结合了定长和变长两种编码方法的特点。它的编码规则很简单:基本平面的字符占用 2 个字节,辅助平面的字符占用 4 个字节。也就是说,UTF-16 的编码长度要么是 2 个字节(U+0000 到 U+FFFF),要么是 4 个字节(U+010000 到 U+10FFFF)。那么问题来了,当我们遇到两个字节时,到底是把这两个字节当作一个字符还是与后面的两个字节一起当作一个字符呢?
这里有一个很巧妙的地方,在基本平面内,从 U+D800 到 U+DFFF 是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。
辅助平面的字符位共有 2^20 个,因此表示这些字符至少需要 20 个二进制位。UTF-16 将这 20 个二进制位分成两半,前 10 位映射在 U+D800 到 U+DBFF(空间大小 2^10),称为高位(H),后 10 位映射在 U+DC00 到 U+DFFF(空间大小 2^10),称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。
因此,当我们遇到两个字节,发现它的码点在 U+D800 到 U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00 到 U+DFFF 之间,这四个字节必须放在一起解读。
接下来,以汉字””为例,说明 UTF-16 编码方式是如何工作的。
汉字””的 Unicode 码点为 0x20BB7,该码点显然超出了基本平面的范围(0x0000 - 0xFFFF),因此需要使用四个字节表示。首先用 0x20BB7 - 0x10000 计算出超出的部分,然后将其用 20 个二进制位表示(不足前面补 0 ),结果为 0001000010 1110110111。接着,将前 10 位映射到 U+D800 到 U+DBFF 之间,后 10 位映射到 U+DC00 到 U+DFFF 即可。U+D800 对应的二进制数为 1101100000000000,直接填充后面的 10 个二进制位即可,得到 1101100001000010,转成 16 进制数则为 0xD842。同理可得,低位为 0xDFB7。因此得出汉字””的 UTF-16 编码为 0xD842 0xDFB7。
Unicode3.0 中给出了辅助平面字符的转换公式:
H = Math.floor((c-0x10000) / 0x400)+0xD800
L = (c - 0x10000) % 0x400 + 0xDC00
根据编码公式,可以很方便的计算出字符的 UTF-16 编码。
以 字符为例,它是一个辅助平面字符,码点为 U+1D306,将其转为 UTF-16 的计算过程如下。
H = Math.floor((0x1D306-0x10000)/0x400)+0xD800 = 0xD834
L = (0x1D306-0x10000) % 0x400+0xDC00 = 0xDF06
所以,字符的 UTF-16 编码就是 0xD834 0xDF06,长度为四个字节。
UTF-32
UTF-32 是最直观的编码方法,每个码点使用四个字节表示,字节内容一一对应码点。比如,码点 0 就用四个字节的 0 表示,码点 597D 就在前面加两个字节的 0。
U+0000 = 0x0000 0000
U+597D = 0x0000 597D
UTF-32 的优点在于,转换规则简单直观,查找效率高。缺点在于浪费空间,同样内容的英语文本,它会比 ASCII 编码大四倍。这个缺点很致命,导致实际上没有人使用这种编码方法,HTML 5 标准就明文规定,网页不得编码成 UTF-32。
JavaScript 编码方法
JavaScript 语言采用 Unicode 字符集,但是只支持一种编码方法。
这种编码既不是 UTF-16,也不是 UTF-8,更不是 UTF-32。上面那些编码方法,JavaScript 都不用。
JavaScript 用的是 UCS-2!
UCS-2 编码
怎么突然杀出一个 UCS-2?这就需要讲一点历史。
互联网还没出现的年代,曾经有两个团队,不约而同想搞统一字符集。一个是 1988 年成立的 Unicode 团队,另一个是 1989 年成立的 UCS 团队。等到他们发现了对方的存在,很快就达成一致:世界上不需要两套统一字符集。
1991 年 10 月,两个团队决定合并字符集。也就是说,从今以后只发布一套字符集,就是 Unicode,并且修订此前发布的字符集,UCS 的码点将与 Unicode 完全一致。
UCS 的开发进度快于 Unicode,1990 年就公布了第一套编码方法 UCS-2,使用 2 个字节表示已经有码点的字符。(那个时候只有一个平面,就是基本平面,所以 2 个字节就够用了。)UTF-16 编码迟至 1996 年 7 月才公布,明确宣布是 UCS-2 的超集,即基本平面字符沿用 UCS-2 编码,辅助平面字符定义了 4 个字节的表示方法。
两者的关系简单说,就是 UTF-16 取代了 UCS-2,或者说 UCS-2 整合进了 UTF-16。所以,现在只有 UTF-16,没有 UCS-2。
那么,为什么 JavaScript 不选择更高级的 UTF-16,而用了已经被淘汰的 UCS-2 呢?
答案很简单:非不想也,是不能也。因为在 JavaScript 语言出现的时候,还没有 UTF-16 编码。
JavaScript 字符函数的局限
由于 JavaScript 只能处理 UCS-2 编码,造成所有字符在这门语言中都是 2 个字节,如果是 4 个字节的字符,会当作两个双字节的字符处理。JavaScript 的字符函数都受到这一点的影响,无法返回正确结果。
以””字符为例,它的 UTF-16 编码是 4 个字节的 0xD834 0xDF06。问题就来了,4 个字节的编码不属于 UCS-2,JavaScript 不认识,只会把它看作单独的两个字符 U+D834 和 U+DF06。前面说过,这两个码点是空的,所以 JavaScript 会认为是两个”�”字符组成的字符串!
"".length
// 2
'\u1D306' === ''
// false
"".charAt(0)
// "�"
"".charCodeAt(0)
// 55348(0xD834)
"" === '\uD834\uDF06'
// true
上面代码表示,JavaScript 认为字符的长度是 2,取到的第一个字符是空字符,取到的第一个字符的码点是 0xDB34。这些结果都不正确!
解决这个问题,必须对码点做一个判断,然后手动调整。下面是正确的遍历字符串的写法。
while (++index < length) {
// ...
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
output.push(character + string.charAt(++index));
} else {
output.push(character);
}
}
类似的问题存在于所有的 JavaScript 字符操作函数。
String.prototype.replace()
String.prototype.substring()
String.prototype.slice()
…
上面的函数都只对 2 字节的码点有效。要正确处理 4 字节的码点,就必须逐一部署自己的版本,判断一下当前字符的码点范围。
ECMAScript 6 中对 Unicode 的扩展
字符的 Unicode 表示法
ES6 加强了对 Unicode 的支持,允许采用\uxxxx 形式表示一个字符,其中 xxxx 表示字符的 Unicode 码点。
"\u0061"
// "a"
但是,这种表示法只限于码点在\u0000~\uFFFF 之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
"\uD842\uDFB7"
// ""
"\u20BB7"
// "₻7"
上面代码表示,如果直接在\u 后面跟上超过 0xFFFF 的数值(比如\u20BB7),JavaScript 会理解成\u20BB+7。所以会显示一个其他字符,后面跟着一个 7。
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
"\u{20BB7}"
// ""
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true
上面代码中,最后一个例子表明,大括号表示法与四字节的 UTF-16 编码是等价的。
有了这种表示法之后,JavaScript 共有 6 种方法可以表示一个字符。
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true
字符串的遍历器接口
ES6 为字符串添加了遍历器接口,使得字符串可以被 for…of 循环遍历。
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
除了遍历字符串,这个遍历器最大的优点是可以识别大于 0xFFFF 的码点,传统的 for 循环无法识别这样的码点。
let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// ""
上面代码中,字符串 text 只有一个字符,但是 for 循环会认为它包含两个字符(都不可打印),而 for…of 循环会正确识别出这一个字符。
直接输入 U+2028 和 U+2029
JavaScript 字符串允许直接输入字符,以及输入字符的转义形式。举例来说,“中”的 Unicode 码点是 U+4e2d,你可以直接在字符串里面输入这个汉字,也可以输入它的转义形式\u4e2d,两者是等价的。
'中' === '\u4e2d' // true
但是,JavaScript 规定有 5 个字符,不能在字符串里面直接使用,只能使用转义形式。
U+005C:反斜杠(reverse solidus)
U+000D:回车(carriage return)
U+2028:行分隔符(line separator)
U+2029:段分隔符(paragraph separator)
U+000A:换行符(line feed)
举例来说,字符串里面不能直接包含反斜杠,一定要转义写成\或者\u005c。
这个规定本身没有问题,麻烦在于 JSON 格式允许字符串里面直接使用 U+2028(行分隔符)和 U+2029(段分隔符)。这样一来,服务器输出的 JSON 被 JSON.parse 解析,就有可能直接报错。
const json = '"\u2028"';
JSON.parse(json); // 可能报错
JSON 格式已经冻结(RFC 7159),没法修改了。为了消除这个报错,ES2019 允许 JavaScript 字符串直接输入 U+2028(行分隔符)和 U+2029(段分隔符)。
const PS = eval(“‘\u2029’”); 根据这个提案,上面的代码不会报错。
注意,模板字符串现在就允许直接输入这两个字符。另外,正则表达式依然不允许直接输入这两个字符,这是没有问题的,因为 JSON 本来就不允许直接包含正则表达式。
JSON.stringify() 的改造
根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的 JSON.stringify()方法有可能返回不符合 UTF-8 标准的字符串。
具体来说,UTF-8 标准规定,0xD800 到 0xDFFF 之间的码点,不能单独使用,必须配对使用。比如,\uD834\uDF06 是两个码点,但是必须放在一起配对使用,代表字符 。这是为了表示码点大于 0xFFFF 的字符的一种变通方法。单独使用\uD834 和\uDFO6 这两个码点是不合法的,或者颠倒顺序也不行,因为\uDF06\uD834 并没有对应的字符。
JSON.stringify()的问题在于,它可能返回 0xD800 到 0xDFFF 之间的单个码点。
JSON.stringify(’\u{D834}’) // “\u{D834}”
为了确保返回的是合法的 UTF-8 字符,ES2019 改变了 JSON.stringify()的行为。如果遇到 0xD800 到 0xDFFF 之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""
字符串处理函数
ES6 新增了几个专门处理 4 字节码点的函数。
String.fromCodePoint():从 Unicode 码点返回对应字符
因为 fromCodePoint() 是 String 的一个静态方法,所以只能通过 String.fromCodePoint() 这样的方式来使用,不能在你创建的 String 对象实例上直接调用。
String.fromCodePoint(42); // "*"
String.fromCodePoint(65, 90); // "AZ"
String.fromCodePoint(0x404); // "\u0404"
String.fromCodePoint(0x2F804); // "\uD87E\uDC04"
String.fromCodePoint(194564); // "\uD87E\uDC04"
String.fromCodePoint(0x1D306, 0x61, 0x1D307) // "\uD834\uDF06a\uD834\uDF07"
String.fromCodePoint('_'); // RangeError
String.fromCodePoint(Infinity); // RangeError
String.fromCodePoint(-1); // RangeError
String.fromCodePoint(3.14); // RangeError
String.fromCodePoint(3e-2); // RangeError
String.fromCodePoint(NaN); // RangeError
String.prototype.codePointAt():从字符返回对应的码点
如果在指定的位置没有元素则返回 undefined 。如果在索引处开始没有 UTF-16 代理对,将直接返回在那个索引处的编码单元。
Surrogate Pair 是 UTF-16 中用于扩展字符而使用的编码方式,是一种采用四个字节(两个 UTF-16 编码)来表示一个字符,称作代理对。
'ABC'.codePointAt(1); // 66
'\uD800\uDC00'.codePointAt(0); // 65536
'XYZ'.codePointAt(42); // undefined
正则表达式
ES6 提供了 u 修饰符,对正则表达式添加 4 字节码点的支持。
/^.$/.test('')
false
/^.$/u.test('')
true
Unicode 正规化
有些字符除了字母以外,还有附加符号。比如,汉语拼音的 Ǒ,字母上面的声调就是附加符号。对于许多欧洲语言来说,声调符号是非常重要的。
Unicode 提供了两种表示方法。一种是带附加符号的单个字符,即一个码点表示一个字符,比如 Ǒ 的码点是 U+01D1;另一种是将附加符号单独作为一个码点,与主体字符复合显示,即两个码点表示一个字符,比如 Ǒ 可以写成 O(U+004F) + ˇ(U+030C)。
// 方法一
'\u01D1'
// 'Ǒ'
// 方法二
'\u004F\u030C'
// 'Ǒ'
这两种表示方法,视觉和语义都完全一样,理应作为等同情况处理。但是,JavaScript 无法辨别。
'\u01D1'==='\u004F\u030C'
//false
ES6 提供了 normalize 方法,允许”Unicode 正规化”,即将两种方法转为同样的序列。
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
// true
Emoji 表情符号的储存
在 Android 手机或者 iPhone 的各种输入法键盘中,会自带一些 Emoji 表情符号,如 IPhone 手机系统键盘包含的表情符号有:
如果在移动端发布文本内容时包含了这种 Emoji 表情符号,通过接口传递到服务器端,服务器端再存入 MySQL 数据库:
对 gbk 字符集的数据库,写入数据库的数据,在回显时,变成 ‘口口’ 无法回显;
对 utf8 字符集的数据库,则根本无法写入数据库,程序直接报出异常信息 java.io.exception xxxxxxxx.
原因分析:
这是由于字符集不支持的异常,因为 Emoji 表情是四个字节,而 mysql 的 utf-8 编码最多三个字节,所以导致数据插不进去。
真正的 utf8 编码(大家都使用的标准),最大支持 4 个 bytes。正是由于 mysql 的 utf8 少一个 byte,导致中文的一些特殊字符和 emoji 都无法正常的显示。mysql 真正的 utf8 其实是 utf8mb4,这是在 5.5.3 版本之后加入的。而目前的“utf8”其实是 utf8mb3。所以尽量不要使用默认的 utf8,使用 utf8mb4 才是正确的选择。
从 mysql 5.5.3 之后版本基本可以无缝升级到 utf8mb4 字符集。同时,utf8mb4 兼容 utf8 字符集,utf8 字符的编码、位置、存储在 utf8mb4 与 utf8 字符集里一样的,不会对有现有数据带来损坏。
作者:怀若先生 链接:https://www.jianshu.com/p/9c9073e601d7
优惠劵
Three_ST
关注
关注
23
点赞
踩
71
收藏
觉得还不错?
一键收藏
知道了
0
评论
计算机基础知识之Unicode-彻底弄懂 Unicode 编码
彻底弄懂 Unicode 编码前言为什么要有编码?大家需要明确的是在计算机里所有的数据都是字节的形式存储、处理的。我们需要这些字节来表示计算机里的信息。但是这些字节本身又是没有任何意义的,所以我们需要对这些字节赋予实际的意义。所以才会制定各种编码标准。编码模型首先需要明确的是存在两种编码模型A:简单字符集在这种编码模型里,一个字符集定义了这个字符集里包含什么字符,同时把每个字符如何对应成计算机里的比特也进行了定义。例如 ASCII,在 ASCII 里直接定义了 A -> 0100 000
复制链接
扫一扫
专栏目录
unicode-math:用于使用 unicodeOpenType 数学字体的 XeLaTeXLuaLaTeX 包
05-30
UNICODE-MATH 包
这个包为 XeLaTeX 和 LuaLaTeX 提供了 Unicode/OpenType 数学的实现。
虽然我对鼓励人们将这个包用于生产工作有点担心,但我知道它有一定的用途,并且正在将其用于分发。 您的测试和反馈对于填补我遗漏的许多空白至关重要!
请注意,此软件包正在持续开发中,不应将界面和功能视为完全稳定。 但是,使用的软件包越多,它将变得越稳定。 (现在一切正常;未来可能会发生变化的只是细节。)
以下免费字体目前支持 Unicode 数学:
(Bogusław Jackowski, Janusz M. Nowacki)
(B. Jackowski、P. Strzelczyk 和 P. Pianowski)
(B. Jackowski,P.Strzelczyk和P.Pianowski)
(B. Jackowski、P. Strzelczyk
Unicode编码详解(一):Unicode简介及其分类
黄邦勇帅的博客
12-31
10万+
Unicode编码详解(一):Unicode简介及其分类
若觉得本文写得还可以,请多多关注本人所作书籍《C++语法详解》电子工业出版社出版,网盘地址:
https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg
本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)
一、基本知识
1、Unicode
Unicode又称为统一码、万国码、单一码,是国际组织制定的旨在容纳全球所有字符的编码方案,包括字符集、编码方案等,它为每种语言中的每个字符设定了统一且唯一的二
参与评论
您还未登录,请先
登录
后发表或查看评论
2023年CSDN年终总结:长风破浪会有时,风物长宜放眼量
FRIGIDWINTER的博客
01-29
1796
回首2023,感谢努力的自己
Unicode编码转UTF-8编码程序
05-08
Unicode转UTF-8
Unicode编码在JavaScript中的作用是什么?
木木木森林
10-26
1013
Unicode编码
在字符串中,使用转义字符输出Unicode编码
\u + 4位编码
console.log("0031"); //返回:0031
加 \u 表示这个是Unicode编码
console.log("\u0031"); //返回:1
Unicode编码详解
枫林晚的博客
07-30
1万+
Unicode定义:
Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
ASCll码与Unicode编码不同
对于很多初学者来说,特别容易将这两个概念混淆,认为ASCLL码就是Unicod...
Unicode详解(附UTF-8、UTF-16和UTF-32)
葉無聞
08-16
9490
Unicode
在百度百科上,对Unicode的介绍是这样的:
“ Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。”
Unicode源于一个很简单的想法:将全世界所有的字符包含在一...
最全解读Unicode字符编码
qq_245375716的博客
06-06
5964
Java 字符编码Unicode 字符编码
Unicode(http://www.unicode.org/versions/#TUS_Latest_Version) 是一个编码方案,说白了希望给世界上每一种文字系统的每一个字符,都分配一个唯一的整数,这样就不可能有任何冲突了。
一、字符编码规范
1.1 ASCII(American Standard Code for Information Interchange)
美国信息交换标准代码,这是计算机上最早使用的通用的编码方案。那个时候计算机还只是拉丁文字
unicode详解
b1049112625的博客
12-14
1945
unicode的中文翻译为统一码,也叫万国码、单一码,由统一码联盟开发,是计算机科学领域里的一项业界标准。简单的来看,unicode就是一个数字,每一个数字对应一个字符的编码,这个字符囊括了整个世界使用的全部语言和符号的字符,所以,从根本上来说,unicode就是一个映射表,一个从数字到文字的映射。
彻底弄懂 Unicode 编码
热门推荐
hezh1994的博客
12-26
13万+
查看原文
今天,在学习 Node.js 中的 Buffer 对象时,注意到它的 alloc 和 from 方法会默认用 UTF-8 编码,在数组中每位对应 1 字节的十六进制数。想到了之间学习 ES6 时关于字符串的 Unicode 表示法,突然就很想知道 UTF-16 是如何进行编码的,我尝试将一些汉字转换成二进制数,然后简单的按 2 个字节一组转换成十六进制,发现对于那些码点较大的汉字,结果
UniCode 常用字符大全
weixin_40899924的博客
09-07
5376
Unicode 常用字符
unicode-bidirectional:Unicode 9.0.0双向算法的Javascript实现
02-04
unicode-bidirectional声明为通用模块( ),这意味着它可以与所有常规Javascript模块系统一起使用: 1. ES6 import { resolve , reorder } from 'unicode-bidirectional' ; const codepoints = [ 0x28 , 0x29 , 0x...
趣谈Unicode、Ascii、utf-8、GB2312、GBK等编码知识
10-25
主要介绍了趣谈Unicode、Ascii、utf-8、GB2312、GBK等编码知识,文章写的诙谐风趣,膜拜啊,需要的朋友可以参考下
计算机基础知识-编码表.doc
06-04
计算机基础知识-编码表 模块:计算机基础知识 主题:编码表 关键词:ASCII、Unicode、UTF-8 1、编码表 计算机发明之初,用来解决数字计算的问题,后来人们发现可以做更多的事,但由 于计算机只识" 数",因此人们必须...
MATLAB的语音滤波设计.zip
03-15
MATLAB课题,课题为基本框架思路,提供答疑设计,不收费,积分默认0,如需积分,为自动上浮,需要的可自行下载,祝学习愉快!
MATLAB家居防火识别系统.zip
03-15
MATLAB课题,课题为基本框架思路,提供答疑设计,不收费,积分默认0,如需积分,为自动上浮,需要的可自行下载,祝学习愉快!
动力节点Java Web知识笔记
03-15
动力节点Java Web知识笔记
pandas_plink-1.2.30-cp37-cp37m-macosx_10_6_intel.whl
03-15
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
pandas_plink-2.0.5-cp38-cp38-manylinux2010_x86_64.whl
最新发布
03-15
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
java 编码 unicode_java编码-Unicode
05-14
Java使用Unicode编码表示字符。Unicode编码是一种标准的字符编码方案,它是一个国际标准,将世界上所有的字符都进行了编码。Java中的Unicode编码采用16进制表示,每个字符用两个字节表示,也就是16位二进制数表示一...
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
Three_ST
CSDN认证博客专家
CSDN认证企业博客
码龄9年
暂无认证
253
原创
5万+
周排名
1万+
总排名
38万+
访问
等级
4514
积分
144
粉丝
172
获赞
83
评论
823
收藏
私信
关注
热门文章
工业相机视野与分辨率计算(相机选型与计算)
54918
C# VSCode创建C#项目
33693
HTML5 实现页面滚动
20667
MacBook Pro macOS 安装 Linux 双系统教程(一)
17402
C# 未将对象引用设置到对象的实例、未经处理的异常报错。
15499
分类专栏
笔记
27篇
计算机基础
48篇
工具
13篇
sql
2篇
Web
24篇
人脸识别
3篇
leetcode
38篇
Angular
6篇
HybridApp
2篇
CSS
12篇
数据分析
1篇
Selenium
2篇
tcp/ip
5篇
Docker
5篇
nosql
1篇
redis
1篇
设计模式
1篇
ASP.NET
14篇
node
19篇
Python
6篇
工业相机
4篇
C#
24篇
WPF
5篇
SQLServer
1篇
git
7篇
Java
40篇
Web前端
73篇
JavaScript
98篇
编程思想
35篇
MySQL
2篇
Android
6篇
Linux
16篇
数据结构
72篇
vue
4篇
剑指Offer
42篇
最新评论
基于C#的TCP/IP socket PLC 通信上位机程序-使用WPF实现(源代码)
Three_ST:
可能是因为网络原因 我看看 这个可以直接下载代码
基于C#的TCP/IP socket PLC 通信上位机程序-使用WPF实现(源代码)
qq_37150021:
链接看不了了
pytorch与cuda环境安装操作
CSDN-Ada助手:
推荐 Python入门 技能树:https://edu.csdn.net/skill/python?utm_source=AI_act_python
MacBook Pro macOS 安装 Linux 双系统教程(一)
Three_ST:
你好,搜廿二一与三二一 4k-macbook pro 安装 Linux pro记录
MacBook Pro macOS 安装 Linux 双系统教程(一)
梅玖玖-sunny:
您好,b站您的同名用户和同文章名视频/类似视频没有找到,方便大神补充一下烧制时候清空盘下一步的代码吗?
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
编译原理学习之-一个简单的语法制导翻译器
linux中crontab编写自动化定时脚本无法正确运行(问题解决与汇总)附相关内容
pytorch与cuda环境安装操作
2024年2篇
2023年21篇
2022年49篇
2021年48篇
2020年55篇
2019年88篇
2018年20篇
目录
目录
分类专栏
笔记
27篇
计算机基础
48篇
工具
13篇
sql
2篇
Web
24篇
人脸识别
3篇
leetcode
38篇
Angular
6篇
HybridApp
2篇
CSS
12篇
数据分析
1篇
Selenium
2篇
tcp/ip
5篇
Docker
5篇
nosql
1篇
redis
1篇
设计模式
1篇
ASP.NET
14篇
node
19篇
Python
6篇
工业相机
4篇
C#
24篇
WPF
5篇
SQLServer
1篇
git
7篇
Java
40篇
Web前端
73篇
JavaScript
98篇
编程思想
35篇
MySQL
2篇
Android
6篇
Linux
16篇
数据结构
72篇
vue
4篇
剑指Offer
42篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
添加红包
祝福语
请填写红包祝福语或标题
红包数量
个
红包个数最小为10个
红包总金额
元
红包金额最低5元
余额支付
当前余额3.43元
前往充值 >
需支付:10.00元
取消
确定
下一步
知道了
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝
规则
hope_wisdom 发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
0
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。
余额充值
Unicode 和 UTF-8 有什么区别? - 知乎首页知乎知学堂发现等你来答切换模式登录/注册计算机Unicode(统一码)字符编码编码UTF-8Unicode 和 UTF-8 有什么区别?关注者3,490被浏览1,566,346关注问题写回答邀请回答好问题 1086 条评论分享95 个回答默认排序uuspider沉默并非无知 孤芳只为自赏 关注举一个例子:It's 知乎日报你看到的unicode字符集是这样的编码表:I 0049
t 0074
' 0027
s 0073
0020
知 77e5
乎 4e4e
日 65e5
报 62a5
每一个字符对应一个十六进制数字。计算机只懂二进制,因此,严格按照unicode的方式(UCS-2),应该这样存储:I 00000000 01001001
t 00000000 01110100
' 00000000 00100111
s 00000000 01110011
00000000 00100000
知 01110111 11100101
乎 01001110 01001110
日 01100101 11100101
报 01100010 10100101
这个字符串总共占用了18个字节,但是对比中英文的二进制码,可以发现,英文前9位都是0!浪费啊,浪费硬盘,浪费流量。怎么办?UTF。UTF-8是这样做的:1. 单字节的字符,字节的第一位设为0,对于英语文本,UTF-8码只占用一个字节,和ASCII码完全相同;2. n个字节的字符(n>1),第一个字节的前n位设为1,第n+1位设为0,后面字节的前两位都设为10,这n个字节的其余空位填充该字符unicode码,高位用0补足。这样就形成了如下的UTF-8标记位:0xxxxxxx110xxxxx 10xxxxxx1110xxxx 10xxxxxx 10xxxxxx11110xxx 10xxxxxx 10xxxxxx 10xxxxxx111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx... ...于是,”It's 知乎日报“就变成了:I 01001001
t 01110100
' 00100111
s 01110011
00100000
知 11100111 10011111 10100101
乎 11100100 10111001 10001110
日 11100110 10010111 10100101
报 11100110 10001010 10100101
和上边的方案对比一下,英文短了,每个中文字符却多用了一个字节。但是整个字符串只用了17个字节,比上边的18个短了一点点。下边是课后作业:请将”It's 知乎日报“的GB2312和GBK码(自行google)转成二进制。不考虑历史因素,从技术角度解释为什么在unicode和UTF-8大行其道的同时,GB2312和GBK仍在广泛使用。剧透:一切都是为了节省你的硬盘和流量。编辑于 2015-11-04 07:56赞同 1856106 条评论分享收藏喜欢收起盛世唐朝愿你阅尽大山大河,仍觉人间值得。 关注很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物。他们看到8个开关状态是好的,于是他们把这称为”字节“。再后来,他们又做了一些可以处理这些字节的机器,机器开动了,可以用字节来组合出很多状态,状态开始变来变去。他们看到这样是好的,于是它们就这机器称为”计算机“。开始计算机只在美国用。八位的字节一共可以组合出256(2的8次方)种不同的状态。 他们把其中的编号从0开始的32种状态分别规定了特殊的用途,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作:遇上0×10, 终端就换行;遇上0×07, 终端就向人们嘟嘟叫;遇上0x1b, 打印机就打印反白的字,或者终端就用彩色显示字母。他们看到这样很好,于是就把这些0×20以下的字节状态称为”控制码”。他们又把所有的空 格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号,这样计算机就可以用不同字节来存储英语的文字了。大家看到这样,都感觉 很好,于是大家都把这个方案叫做 ANSI 的”Ascii”编码(American Standard Code for Information Interchange,美国信息互换标准代码)。当时世界上所有的计算机都用同样的ASCII方案来保存英文文字。后来,就像建造巴比伦塔一样,世界各地都开始使用计算机,但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的,为了可以在计算机保存他们的文字,他们决定采用 127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128 到255这一页的字符集被称”扩展字符集“。从此之后,贪婪的人类再没有新的状态可以用了,美帝国主义可能没有想到还有第三世界国家的人们也希望可以用到计算机吧!等中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民,我们不客气地把那些127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312“。GB2312 是对 ASCII 的中文扩展。但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,特别是某些很会麻烦别人的国家领导人。于是我们不得不继续把GB2312 没有用到的码位找出来老实不客气地用上。后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。 中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持,会编程的计算机僧侣们都要每天念下面这个咒语数百遍: “一个汉字算两个英文字符!一个汉字算两个英文字符……”因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,使用着同一种语言的兄弟地区,也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个”汉字系统”,专门用来处理汉字的显示、输入的问题,像是那个台湾的愚昧封建人士写的算命程序就必须加装另一套支持 BIG5 编码的什么”倚天汉字系统”才可以用,装错了字符系统,显示就会乱了套!这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦人民,他们的文字又怎么办? 真是计算机的巴比伦塔命题啊!正在这时,大天使加百列及时出现了——一个叫 ISO(国际标准化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号 的编码!他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode“。unicode开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。这时候,从旧社会里走过来的程序员开始发现一个奇怪的现象:他们的 strlen 函数靠不住了,一个汉字不再是相当于两个字符了,而是一个!是的,从unicode开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符“!同时,也都是统一的”两个字节“,请注意”字符”和”字节”两个术语的不同,“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在unicode中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。unicode同样也不完美,这里就有两个的问题,一个是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储空间来说是极大的浪费,文本文件的大小会因此大出二三倍,这是难以接受的。unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码做为它的一部分,注意的是unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到utf-8并不是直接的对应,而是要过一些算法和规则来转换。Unicode符号范围 | UTF-8编码方式(十六进制) | (二进制)—————————————————————–0000 0000-0000 007F | 0xxxxxxx0000 0080-0000 07FF | 110xxxxx 10xxxxxx0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx最后简单总结一下:中国人民通过对 ASCII 编码的中文扩充改造,产生了 GB2312 编码,可以表示6000多个常用汉字。汉字实在是太多了,包括繁体和各种字符,于是产生了 GBK 编码,它包括了 GB2312 中的编码,同时扩充了很多。中国是个多民族国家,各个民族几乎都有自己独立的语言系统,为了表示那些字符,继续把 GBK 编码扩充为 GB18030 编码。每个国家都像中国一样,把自己的语言编码,于是出现了各种各样的编码,如果你不安装相应的编码,就无法解释相应编码想表达的内容。终于,有个叫 ISO 的组织看不下去了。他们一起创造了一种编码 UNICODE ,这种编码非常大,大到可以容纳世界上任何一个文字和标志。所以只要电脑上有 UNICODE 这种编码系统,无论是全球哪种文字,只需要保存文件的时候,保存成 UNICODE 编码就可以被其他电脑正常解释。UNICODE 在网络传输中,出现了两个标准 UTF-8 和 UTF-16,分别每次传输 8个位和 16个位。于是就会有人产生疑问,UTF-8 既然能保存那么多文字、符号,为什么国内还有这么多使用 GBK 等编码的人?因为 UTF-8 等编码体积比较大,占电脑空间比较多,如果面向的使用人群绝大部分都是中国人,用 GBK 等编码也可以。来源于网络,出处实在无法考证,无法署名,有删减修改,如有侵权请直接联系。可能的原文:unicode,ansi,utf-8,unicode big endian编码的区别,网页编码就是那点事编辑于 2021-05-27 20:40赞同 1.6 万328 条评论分享收藏喜欢
你懂Unicode吗?可以教教我吗? - 知乎首发于脚趾头の胡言乱语切换模式写文章登录/注册你懂Unicode吗?可以教教我吗?脚趾头声明:本文记录的是我第一次零散地入门学习unicode的一些笔记。若有错误请指出想了解Unicode的原因第一,因为项目中遇到几次需要文本处理的场景,但已有代码的处理方式要么错误,要么处理得不完善:比如把utf-8编码的字符串当做ASCII编码的[u8]数组来操作,直接导致后续乱码甚至内存溢出。用下标索引字符,导致无法读出正确的字符。(其实和上面一点类似)自己写了一套分词器,只处理了英语和汉字,但无法处理带标点的单词(that's, can't...)和emoji。处理字符串相等,有的比较字符串的字节,有的逐个比较字符串中的字符相等。但无法正确处理一些注音符号,或者同形异码的字。第二,对unicode中的各种有趣的东西早有耳闻,想了解其中的原理:UTF-8是变长编码神奇的组合“字符”。比如曾一度各家文本编辑器搞崩的注音符号,像"è̀̀̀",这其实是一个e后面跟了四个注音符号"◌̀"(\u{0300})。过分点的像这样"à̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡"。组合的emoji。有些同形异码的“字符”。比如说组合字符"è"(e\u{0300})和"è"(\u{00e8}),汉字一些异体字"串"(\u{4e32})与"串"(\u{F905})等书写方向不一样的字。比如从右到左书写的希伯来语"אבג",实际物理序列是גבא存在连字的字符。比如印度语 नमस्ते 中 स्ते = स् + ते,这是两个“字符”,但是渲染时连在了一起。各种各样的控制字符。这里实际顺序其实还是"各种各样的控制字符",但是前面多加了个从右到左书写的控制字符\u{202e},所以方向就反了。从零开始的UnicodeUnicode和其它字符集,比如ASCII,GBK这些其实包含了更宽广的概念,它是一整套字符的标准。它除了定义了收录字符的字符集以及字符在字符集中的“编号”(一般称为code point,码点)以外,还定义了标准的编码方法、字符串的归一化、拆分、排序、双向文本算法、书写方向、字符特性(比如大小写)等等。(甚至正则语法都是unicode定的标准https://www.unicode.org/reports/tr18,只是大多数语言都没支持全罢了)要入门了解unicode,我觉得主要需要理解两点:第一,unicode不同于其它字符集,unicode中的 字符(character) 与 字符用于存储和传输的编码格式(encode) 两者是分立的。举个例子,ASCII下的字符串就是字符数组,字符的编码格式就是字符在ASCII字符集中码点二进制的值。而unicode标准里定义了多种编码格式,也就是我们常说的UTF-8, UTF-16, UTF-32等,unicode中的字符需要通过编码格式的进一步编码成二进制格式才能用于存储和传输。又因为UTF-8, UTF-16是变长的编码格式,所以unicode中的字符串不再是字符数组了。第二,unicode中的字符并不是人类所感知的视觉上的字符,而是表示人类书写系统中语义单位,主要但不仅限于字母、标点符号、其它语言的符号与部件、科学中使用的记号。视觉上的字符则使用字形(glyph)一词来描述,字形由字体库和渲染程序决定。这两者并不是一一对应的关系:一个字符可以有多个字形,一个字符在不同的环境下可以渲染成不同的形状。更进一步只要是含义相同来源相同的都应该是同一个字符。一个字形可以由多个字符所决定,比如注音的组合字符,emoji等。字符的顺序和文字渲染的方向不一定相同,比如说希伯来文,字符编码从左到右排列(物理存储数顺序),但是是从右到左显示的(逻辑顺序)。这两点本质上是在说字形(glyph) - 字符(character) -编码(encode) 三个概念的分离。那么下文就按照这三者分别展开一下补充了解,Unicode有十条基础准则:1. Universality:提供单一、综合的字符集,编码一切现代与大部分历史文献的字符。2. Efficiency:易于处理与分析。3. Characters, not glyphs:对字符编码,而不是字形。4. Semantics:字符要有良好定义的语义。5. Plain text:仅限于文本字符。6. Logical order:默认内存表示是其逻辑序。7. Unification:把不同语言的同一书写系统(scripts)中相同字符统一起来。8. Dynamic composition:附加符号可以动态组合。9. Stability:已分配的字符与语义不再改变。10. Convertibility:Unicode与其他著名字符集可以精确转换。字符而是表示人类书写系统中语义单位,主要但不仅限于字母、标点符号、其它语言的符号与部件、科学中使用的记号。unicode通过码点来表示一个字符,目前Unicode的码点范围是从0x000000 ~ 0x10FFFF(这意味着至少需要21位或者3个字节来编码)来表示字符,然后这个范围又划分为了17个编码平面,每组平面有65536个码点:平面始末字符值中文名称英文名称0号平面\u{0000} - \u{FFFF}基本多文种平面Basic Multilingual Plane,简称BMP1号平面\u{10000} - \u{1FFFF}多文种补充平面Supplementary Multilingual Plane,简称SMP2号平面\u{20000} - \u{2FFFF}表意文字补充平面Supplementary Ideographic Plane,简称SIP3号平面\u{30000} - \u{3FFFF}表意文字第三平面Tertiary Ideographic Plane,简称TIP4号平面 至 13号平面\u{40000} - \u{DFFFF}(尚未使用)14号平面\u{E0000} - \u{EFFFF}特别用途补充平面Supplementary Special-purpose Plane,简称SSP15号平面\u{F0000} - \u{FFFFF}保留作为私人使用区(A区)Private Use Area-A,简称PUA-A16号平面\u{100000} - \u{10FFFF}保留作为私人使用区(B区)Private Use Area-B,简称PUA-B平面内其中有些我们比较关心的区段:ASCII所在的区段为\u{0000} - \u{007F},在BMP。(使用7位,1个字节就可以编码)。汉字目前在多个平面多个区段收录了将近10万个汉字,不过要注意的是有的区段中还存在没分配的码点:BMP:CJK扩展区A,从\u{3400}-\u{4DBF}CJK中常用汉字,从\u{4E00} -\u{9FFF}, 以及〇 \u{3007}SIP: CJK扩展区B,从\u{20000} - \u{2A6DF}CJK扩展区C,从\u{2A700} - \u{2B73F}CJK扩展区D,从\u{2B740} - \u{2B81F}CJK扩展区E,从\u{2B820} - \u{2CEAF}CJK扩展区F,从\u{2CEB0} - \u{2EBEF}兼容增补区,从\u{2F800} - \u{2FA1F}TIP: CJK扩展区G,从\u{30000} - \u{3134F}CJK扩展区H,从\u{31350} - \u{323AF}汉字其实在unicode里叫中日韩统一表意文字(CJK Unified Ideographs),关于CJK还有很多可以展开的地方,之后有机会学习之后再来聊聊。UTF-16。unicode中预留了两个区段的代码用于UTF-16编码,也叫代理对(Surrogate Pair),具体含义后面再展开。但要关注的是这两个区段的码点并不属于unicode的字符。从\u{D800} - \u{DBFF} 是UTF-16的高位代理从\u{DC00} - \u{DFFF}是UTF-16的低位代理程序语言中,也有类型来专门表示unicode码点的值:Rust语言用char类型来表示字符,其值是字符unicode的码点,4个字节,21位可用,其中'\u{D800}'-'\u{DFFF}'是非法的值,会编译报错。Swift语言用Unicode.Scalar来表示unicode的字符,其值是unicode码点的值。但值得注意的是Character类型并不对应unicode中字符的概念,而是字元簇(grapheme cluster),可能由多个码点组成,近似于用户所感知的字符,这个概念后面再展开。swift同样也会认为'\u{D800}'-'\u{DFFF}'是非法的值,会编译报错。编码此处的编码不是将分配code point给字符的那个编码,而是字符(串)存储、传输的二进制编码格式。根据最小编码单元(code unit)有多少位,unicode 给出了几种标准的编码格式:UTF-8, UTF-16, UTF-32(还有其它的,比如UTF-7,但基本已经都废弃了)。其中UTF-8, UTF-16是变长的编码,因为unicode的字符至少需要21位来编码,所以有些字符就需要多个code unit来来编码,但这牺牲了随机访问字符的能力。而UTF-32是定长的编码,直接将code point映射到32位的code unit中,但也造成了极大的浪费,所以现在基本也不会使用UTF-32这一编码格式。下面展开一下UTF-8, UTF-16两种常用的编码格式UTF-8UTF-8全称是8比特Unicode转换格式(8-bit Unicode Transfomation Format),是目前最通用的unicode编码格式。是一种变长的编码,通过字节前缀区分长度。码点范围码点值(二进制)UTF-8(二进制)备注\u{000000} - \u{00007F}00000000 00000000 0zzzzzzz0zzzzzzz一个字节编码时刚好兼容ASCII\u{000080} - \u{0007FF}00000000 00000yyy yyzzzzzz110yyyyy 10zzzzz大部分欧洲的文字只需要两个字节编码\u{000800} - \u{00D7FF} \u{00E000} - \u{00FFFF}00000000 xxxxyyyy yyzzzzzz1110xxxx 10yyyyyy 10zzzzzz三个字节编码时,因为中间有代理对编码的缘故,中间有一段值是非法的。大部分汉字只需要用三个字节编码就可以了\u{010000} - \u{10FFFF}000wwwxx xxxxyyyy yyzzzzzz11110www 10xxxxxx 10yyyyyy 10zzzzzz辅助平面内的字符需要用四个字节编码,但一般不太常用。举个例子,〇(\u{3007})码点的二进制为00110000 00000100,编码到UTF-8之后,需要三个字节:11100011 10000000 10000100。UTF-16一些比较古早的语言比如Java,字符串内部使用的是UTF-16的编码C++,宽字符类型wchar_t是UTF-16的一个code unit(还不是一个字符),wstring则是UTF-16编码的字符串其规则如下:BMP平面内,用一个code unit编码,其值等于code point的值。比如汉字〇(\u{3007})码点的二进制为00110000 00000100,UTF-16编码仍然是00110000 00000100,占两个字节。比UTF-8编码占用的空间要小——如果你的文本绝大多数都是常用汉字,其实用UTF-16编码会更省空间。同样,\u{D800} - \u{DFFF} (2048个code point)在UTF-16编码中也是不能单独存在的。留作代理对的编码使用其他的字符则用代理对的来编码:首先code point得值减 0x10000,得到的值从0x00000 - 0xFFFFF,占10位其中高10位(从 0x000 - 0x3FF)加上0xD800,得到UTF-16的高位代理,也就是从0xD800 - 0xDBFF剩余低10位(也是从 0x000 - 0x3FF)加上0xDC00,得到UTF-16的低位代理,也就是从0xDC00 - 0xDFFF反正我是觉得这种编码方式还是挺蛋疼的。字形unicode的字符并不表示用户视觉上字符,同样也并没有具体规定字符的字形图案,字形图案由字体库和渲染程序决定(不过会给出一些字体库和渲染程序需要遵守的一些规范)。而对于用户层面上的字符,unicode则通过引入组合字符的概念来表达,可以通过各种组合规则,来构建出复杂的文字。组合字符首先有个事实——人类的文字系统是复杂的,绝大多数文字都无法简单地编码,要么使用庞大的码空间去表示字符,要么引入复杂的字法规则(可能还会有很多corner cases, bad cases)。而一些相对比较简单的使用拉丁字母的书写系统中,也会有带上各种注音符号的情况,如果每种注音符号的组合单独申请一个码点,那估计unicode那么点编码空间瞬间就能被填满。更何况还有复杂情况更多的东南亚南亚或者一些古文字了,而且还致力于将人类所有文字系统都纳入囊中。所以像之前那种通过扩大码空间去放下更多字符做法在unicode中是不适合的。于是unicode中就引入了组合字符的概念。组合字符是在基字符上添加的各种标记,这些标记可以出现在基字符的各个位置,不过物理上的顺序则是 基字符后跟随多个组合字符,那么组合字符表示的标记就会附加在基字符上,这部分就会(应)被渲染器作为一个整体来看待:不过在unicode里,并没有限定一些组合字符的基字符一定是哪类字符,比如说汉字后也可以跟着拉丁字母中的那些注音字符(e.g. 邓̀ = 邓 + ◌̀),有些地方能渲染,有的地方不能,或者不同地方渲染的样子不一样,不过这样虽然在unicode中是合法的,但在书写系统中其实并没有意义。unicode里也同样没有规定一个基字符后可以跟多少个组合字符,所以文章开头那个像是乱码的字符也是合法的,但支持渲染这样字符的地方也没有多少个。正规化(Normalize)我们来探讨一下字符串的比较。其实字符串可以定义多种等价关系,按编码比较,也可以看作是按字符码点逐个比较。按字形比较,也就是两个字符串被渲染成同一个图像时,视为等价。按表达含义比较,但这个很多时候并不是well-defined的。等等在一般的文本处理的场景下,显然是按字形比较更适合更多的场景的,且更符合用户直觉。字形的等价其实可以给出很多种比较方式,unicode里给出了两种:标准等价,也就是两个字符串,要求在相同字体下无论何时渲染器在必须渲染成同一个图像。兼容等价,比标准等价更弱点,只要求两个字符串渲染得像,且意思相近就行。对于unicode来说,不能直接通过比较编码来判断字符串等价,主要是因为有组合字符的原因,下面两种情况按编码比较都不相等:unicode包含了很多的预组合字符(Precomposed Character),比如说上文的"è"(\u{00e8}) 和 "è"(e + ◌̀),他们是标准等价的。unicode中不同组合字符的组合顺序都是合法的,如果组合字符的布局不互相影响,那么这两组组合字符应该被渲染为同一个图像。比如说 ą́ = a + ◌́ + ◌̨,也可以是 ą́ = a + ◌̨ + ◌́,他们是标准等价的。于是unicode标准中给出了四种字符串的正规化(Normalize)形式,在比较两个字符串之前(通过编码比较),需要先对两个字符串进行正规化:名称方式NFD: Normalization Form Canonical Decomposition以标准等价方式来分解,分解将组合字符按标准顺序排序。NFC: Normalization Form Canonical Composition以标准等价方式来分解,然后以标准等价重组之。NFKD: Normalization Form Compatibility Decomposition以兼容等价方式来分解,分解将组合字符按标准顺序排序。NFKC: Normalization Form Compatibility Composition以兼容等价方式来分解,然后以标准等价重组之。字元簇(Grapheme Cluster)unicode的字符虽然并不表示用户视觉上字符,但我们进行大多数文字处理的时候,都需要从用户视角出发,这导致我们无法直接操作unicode字符,这很麻烦。于是unicode提出了字元簇(Grapheme Cluster)来近似用户视觉上的字符,方便开发者使用。比如一组组合字符,一个emoji整体等都会被分在一个字元簇内。swift的Character类型,就是一个字元簇,字元簇(以及String)的比较则是经过了正规化处理后的比较。不过字元簇仍然只是近似的处理,如果在严肃的文字处理的场景,我们仍然需要结合各种东西来处理字符。比如在处理复杂的文字时,像是印度语नमस्ते,这里有6个字符,会被划分为4个字元簇न म स् ते,但是在好的文本编辑器内后面两个会当做一个整体来处理(比如说退格键、高亮等)Belleve: 这个字符串在 char 层面上是这样的:na、ma、sa、virama、ta、e,grapheme cluster 为四个:na、ma、sa-virama、ta-e,但是第三个 cluster 因为以 virama 结尾因此是一个 half form,会和后面的 ta-e 在编辑的时候做一个整体处理(如果字体支持 sta 的 akhand conjunction 的话就会进一步连接在一起)同样的情况还出现在其它语言中,这与文字对应语言的规则和字体相关的,这些语言字符和词之间的界限相对来说比较模糊。而有的情况则是和字体有关,字体库会让一些字符连在一起显示,比如说在程序员常用的fira code,比如->会显示成→,!=会显示为≠等等:书写方向这里我偷懒也不写了。总之unicode在一些不同书写方向的文字的混合排版给了一套双向排版的算法,具体算法就不展开了。Unicode历史债unicode已经是1991年推出的标准了,尽管每隔一段时间都会更新下版本,但里面还是包含了不少历史债,或者不太合理的地方。这里只是简单举一些:有些字母的斜体粗体下划线之类的,明显应该是字体库和排版软件去完成,但是unicode却把这些字符编进了字符集里。而事实上在富文本的编辑器中我们几乎不会去使用这些符号有些因为历史问题,造成了编码的重复,出现了一字多码的情况,破坏了unicode一字一码的设计原则。汉字里就有很多情况,比如说“戶”、“户”、“戸”。收录了一些根本不存在的汉字,比如说“彁”还有很多很多汉字都没有收录到unicode里等等。。参考core spec: https://www.unicode.org/versions/Unicode15.0.0/UnicodeStandard-15.0.pdfhttps://unicode.org/reports/tr29/https://zh.wikipedia.org/wiki/%E4%B8%AD%E6%97%A5%E9%9F%93%E7%B5%B1%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97https://www.zhihu.com/question/320709601/answer/2278103162https://zhuanlan.zhihu.com/p/53714077 编辑于 2023-10-07 10:45・IP 属地广东Unicode(统一码)赞同 315 条评论分享喜欢收藏申请转载文章被以下专栏收录脚趾头の胡言乱语脚趾头想不到时的胡言乱语,脚趾头对此
What is Unicode? in Simplified Chinese
什
么是Unicode(统一码)?
Home
| Site
Map |
Search
What is Unicode?
What
is
Unicode? in English (This page has links to many other
translations.)
Display Problems
Depending on the level of
Unicode
support in the browser you are using and whether or not you
have the
necessary fonts installed, you may have display problems for
some of
the translations, particularly with complex scripts such as
Arabic.
For further information, see
Display
Problems.
More Information
The
Unicode Standard
Technical
Introduction
Glossary
Useful
Resources
Unicode
Consortium
Contacting Unicode
什么是Unicode(统一码)?
Unicode给每个字符提供了一个唯一的数字,
不论是什么平台、
不论是什么程序、
不论是什么语言。
基本上,计算机只是处理数字。它们指定一个数字,来储存字母或其他字符。在创造Unicode之前,有数百种指定这些数字的编码系统。没有一个编码可以包含足够的字符,例如:单单欧洲共同体就需要好几种不同的编码来包括所有的语言。即使是单一种语言,例如英语,也没有哪一个编码可以适用于所有的字母、标点符号,和常用的技术符号。
这些编码系统也会互相冲突。也就是说,两种编码可能使用相同的数字代表两个不同的字符,或使用不同的数字代表相同的字符。任何一台特定的计算机(特别是服务器)都需要支持许多不同的编码,但是,不论什么时候数据通过不同的编码或平台之间,那些数据总会有损坏的危险。
Unicode正在改变所有这一切!
Unicode给每个字符提供了一个唯一的数字,不论是什么平台、不论是什么程序、不论什么语言。Unicode标准已经被这些工业界的领导们所采用,例
如:Apple, HP, IBM, JustSystem, Microsoft, Oracle, SAP, Sun, Sybase, Unisys和其他许多公司。
最新的标准都需要Unicode,例如XML,
Java, ECMAScript (JavaScript), LDAP, CORBA 3.0,
WML等等,并且,Unicode是实现ISO/IEC 10646的正规方式。许多操作系统、所有最新的浏览器和许多其他产品都支持它。
Unicode标准的出现和支持它工具的存在,是近来全球软件技术最重要的发展趋势。
将Unicode与客户服务器或多层应用程序和网站结合,比使用传统字符集节省费用。Unicode使单一软件产品或单一网站能够贯穿多个平台、语言和国
家,而不需要重建。它可将数据传输到许多不同的系统,而无损坏。
关于Unicode学术学会
Unicode学术学会是一个非盈利的501(c)(3)慈善组织,是为发展、扩展和推广使用Unicode标准而建立的,Unicode学术学会设立了现代软件产品和标准文本的表示法。学术学会的会员代表了广泛领域的计算机和资讯工业的公司和组织。学术学会只由会员提供资金。Unicode学
术学会的会员资格开放给世界上
任何支持Unicode标准和希望协助其扩展和执行的组织及个人。大家都可通过捐赠来支持学术学会的重要工作。
欲知更多信息,请参阅术语词汇
表 、技术简介和参考资料。
Chinese translation by Jenny K. Pan 黎國珍, Xerox, updated by 洛杉矶翻译
一篇文章就能懂什么是Unicode编码 - 小燃、 - 博客园
会员
周边
新闻
博问
AI培训
云市场
所有博客
当前博客
我的博客
我的园子
账号设置
简洁模式 ...
退出登录
注册
登录
qrr
博客园
首页
新随笔
联系
订阅
管理
一篇文章就能懂什么是Unicode编码
转载自:https://blog.csdn.net/zhusongziye/article/details/84261211
Unicode编码!?
想必做过爬虫的同学肯定被编码问题困扰过,有 UTF-8、GBK、Unicode 等等编码方式,但你真的了解其中的原理吗?下面我们就来了解一下 Unicode 和 UTF-8 编码到底有什么关系。
要弄清 Unicode 与 UTF-8 的关系,我们还得从他们的来源说起,下来我们从刚开始的编码说起,直到 Unicode 的出现,我们就会感觉到他们之间的关系
ASCII码
我们都知道,在计算机的世界里,信息的表示方式只有 0 和 1,但是我们人类信息表示的方式却与之大不相同,很多时候是用语言文字、图像、声音等传递信息的。
那么我们怎样将其转化为二进制存储到计算机中,这个过程我们称之为编码。更广义地讲就是把信息从一种形式转化为另一种形式的过程。
我们知道一个二进制有两种状态:”0” 状态 和 “1”状态,那么它就可以代表两种不同的东西,我们想赋予它什么含义,就赋予什么含义,比如说我规定,“0” 代表 “吃过了”, “1”代表 “还没吃”。
这样,我们就相当于把现实生活中的信息编码成二进制数字了,并且这个例子中是一位二进制数字,那么 2 位二进制数可以代表多少种情况能?对,是四种,2^2,分别是 00、01、10、11,那 7 种呢?答案是 2^7=128。
我们知道,在计算机中每八个二进制位组成了一个字节(Byte),计算机存储的最小单位就是字节,字节如下图所示 :
所以早期人们用 8 位二进制来编码英文字母(最前面的一位是 0),也就是说,将英文字母和一些常用的字符和这 128 中二进制 0、1 串一一对应起来,比如说 大写字母“A”所对应的二进制位“01000001”,转换为十六进制为 41。
在美国,这 128 是够了,但是其他国家不答应啊,他们的字符和英文是有出入的,比如在法语中在字母上有注音符号,如 é ,这个怎么表示成二进制?
所以各个国家就决定把字节中最前面未使用的那一个位拿来使用,原来的 128 种状态就变成了 256 种状态,比如 é 就被编码成 130(二进制的 10000010)。
为了保持与 ASCII 码的兼容性,一般最高为为 0 时和原来的 ASCII 码相同,最高位为 1 的时候,各个国家自己给后面的位 (1xxx xxxx) 赋予他们国家的字符意义。
但是这样一来又有问题出现了,不同国家对新增的 128 个数字赋予了不同的含义,比如说 130 在法语中代表了 é,但是在希伯来语中却代表了字母 Gimel(这不是希伯来字母,只是读音翻译成英文的形式)具体的希伯来字母 Gimel 看下图
所以这就成了不同国家有不同国家的编码方式,所以如果给你一串二进制数,你想要解码,就必须知道它的编码方式,不然就会出现我们有时候看到的乱码 。
Unicode的出现
Unicode 为世界上所有字符都分配了一个唯一的数字编号,这个编号范围从 0x000000 到 0x10FFFF (十六进制),有 110 多万,每个字符都有一个唯一的 Unicode 编号,这个编号一般写成 16 进制,在前面加上 U+。例如:“马”的 Unicode 是U+9A6C。
Unicode 就相当于一张表,建立了字符与编号之间的联系
它是一种规定,Unicode 本身只规定了每个字符的数字编号是多少,并没有规定这个编号如何存储。
有的人会说了,那我可以直接把 Unicode 编号直接转换成二进制进行存储,是的,你可以,但是这个就需要人为的规定了,而 Unicode 并没有说这样弄,因为除了你这种直接转换成二进制的方案外,还有其他方案,接下来我们会逐一看到。
编号怎么对应到二进制表示呢?有多种方案:主要有 UTF-8,UTF-16,UTF-32。
1、UTF-32
先来看简单的 UTF-32
这个就是字符所对应编号的整数二进制形式,四个字节。这个就是直接转换。 比如马的 Unicode 为:U+9A6C,那么直接转化为二进制,它的表示就为:1001 1010 0110 1100。
这里需要说明的是,转换成二进制后计算机存储的问题,我们知道,计算机在存储器中排列字节有两种方式:大端法和小端法,大端法就是将高位字节放到底地址处,比如 0x1234, 计算机用两个字节存储,一个是高位字节 0x12,一个是低位字节 0x34,它的存储方式为下:
UTF-32 用四个字节表示,处理单元为四个字节(一次拿到四个字节进行处理),如果不分大小端的话,那么就会出现解读错误,比如我们一次要处理四个字节 12 34 56 78,这四个字节是表示 0x12 34 56 78 还是表示 0x78 56 34 12?不同的解释最终表示的值不一样。
我们可以根据他们高低字节的存储位置来判断他们所代表的含义,所以在编码方式中有 UTF-32BE 和 UTF-32LE,分别对应大端和小端,来正确地解释多个字节(这里是四个字节)的含义。
2、UTF-16
UTF-16 使用变长字节表示
① 对于编号在 U+0000 到 U+FFFF 的字符(常用字符集),直接用两个字节表示。
② 编号在 U+10000 到 U+10FFFF 之间的字符,需要用四个字节表示。
同样,UTF-16 也有字节的顺序问题(大小端),所以就有 UTF-16BE 表示大端,UTF-16LE 表示小端。
3、UTF-8
UTF-8 就是使用变长字节表示,顾名思义,就是使用的字节数可变,这个变化是根据 Unicode 编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多。使用的字节个数从 1 到 4 个不等。
UTF-8 的编码规则是:
① 对于单字节的符号,字节的第一位设为 0,后面的7位为这个符号的 Unicode 码,因此对于英文字母,UTF-8 编码和 ASCII 码是相同的。
② 对于n字节的符号(n>1),第一个字节的前 n 位都设为 1,第 n+1 位设为 0,后面字节的前两位一律设为 10,剩下的没有提及的二进制位,全部为这个符号的 Unicode 码 。
举个例子:比如说一个字符的 Unicode 编码是 130,显然按照 UTF-8 的规则一个字节是表示不了它(因为如果是一个字节的话前面的一位必须是 0),所以需要两个字节(n = 2)。
根据规则,第一个字节的前 2 位都设为 1,第 3(2+1) 位设为 0,则第一个字节为:110X XXXX,后面字节的前两位一律设为 10,后面只剩下一个字节,所以后面的字节为:10XX XXXX。
所以它的格式为 110XXXXX 10XXXXXX 。
下面我们来具体看看具体的 Unicode 编号范围与对应的 UTF-8 二进制格式
那么对于一个具体的 Unicode 编号,具体怎么进行 UTF-8 的编码呢?
首先找到该 Unicode 编号所在的编号范围,进而可以找到与之对应的二进制格式,然后将该 Unicode 编号转化为二进制数(去掉高位的 0),最后将该二进制数从右向左依次填入二进制格式的 X 中,如果还有 X 未填,则设为 0 。
比如:“马”的 Unicode 编号是:0x9A6C,整数编号是 39532,对应第三个范围(2048 - 65535),其格式为:1110XXXX 10XXXXXX 10XXXXXX,39532 对应的二进制是 1001 1010 0110 1100,将二进制填入进入就为:
11101001 10101001 10101100 。
由于 UTF-8 的处理单元为一个字节(也就是一次处理一个字节),所以处理器在处理的时候就不需要考虑这一个字节的存储是在高位还是在低位,直接拿到这个字节进行处理就行了,因为大小端是针对大于一个字节的数的存储问题而言的。
综上所述,UTF-8、UTF-16、UTF-32 都是 Unicode 的一种实现。
posted @
2020-03-15 13:47
小燃、
阅读(5031)
评论(0)
编辑
收藏
举报
会员力量,点亮园子希望
刷新页面返回顶部
公告
Copyright © 2024 小燃、
Powered by .NET 8.0 on Kubernetes
MDN Web 文档术语表:Web 相关术语的定义
AbstractionAccentAccessibilityAccessibility treeAccessible descriptionAccessible nameAdobe FlashAdvance measureAjaxAlgorithmAlignment containerAlignment subjectAlpha (alpha channel)ALPNAPIApple SafariApplication ContextArgumentARIAARPAARPANETArrayASCIIAsynchronousATAGAttributeBandwidthBase64BaselineBeaconBézier curveBiDiBigIntBindingBitwise flagsBlinkBlockBlock cipher mode of operationBlock-level contentBooleanBounding BoxBreadcrumbBrotli compressionBrowserBrowsing contextBufferCacheCacheableCalDAVCall stackCallback functionCamel caseCanonical orderCanvasCard sortingCardDAVCaretCDNCertificate authorityCertifiedChallenge-response authenticationCharacterCharacter encodingCharacter setChromeCIACipherCipher suiteCiphertextClassClickjackingClosureCMSCode pointCode splittingCode unitCodecColor spaceColor wheelCompileCompile timeComposite operationComputer ProgrammingConditionalConstantConstructorContinuous MediaControl flowCookieCopyleftCORSCORS-safelisted request headerCORS-safelisted response headerCrawlerCRLFCross AxisCross-site scripting (XSS)CRUDCryptanalysisCryptographic hash functionCryptographyCSPCSRFCSSCSS Object Model (CSSOM)CSS pixelCSS preprocessorData structureDatabaseDecryptionDeep copyDeltaDenial of ServiceDescriptor (CSS)DeserializationDeveloper ToolsDigestDigital certificateDistributed Denial of ServiceDMZDNSDoctypeDocument directiveDocument environmentDOM (Document Object Model)DomainDomain nameDomain shardingDominatorDoS attackDSLDTLS (Datagram Transport Layer Security)DTMF (Dual-Tone Multi-Frequency signaling)Dynamic typingECMAECMAScriptEffective connection typeElementEncapsulationEncryptionEndiannessEngineEntityEntity headerEnumeratedeTLDEventExceptionEXIFExpandoFallback alignmentFalsyFaviconFetch directiveFetch metadata request headerFingerprintingFirefox OSFirewallFirst contentful paintFirst CPU idleFirst input delayFirst Meaningful PaintFirst paintFirst-class FunctionFlexFlex ContainerFlex ItemFlexboxForbidden header nameForbidden response header nameForkFragmentainerFrame rate (FPS)FTPFTUFunctionFuzz testingGamutGarbage collectionGeckoGeneral headerGIFGitGlobal objectGlobal scopeGlobal variableGlyphGoogle ChromeGPLGPUGraceful degradationGridGrid AreasGrid AxisGrid CellGrid ColumnGrid containerGrid LinesGrid RowGrid TracksGuardGuttersGZip compressionHashHeadHigh-level programming languageHMACHoistingHostHotlinkHoudiniHPKPHSTSHTMLHTML5HTTPHTTP headerHTTP/2HTTP/3HTTPSHTTPS RRHyperlinkHypertextIANAICANNICEIDEIdempotentIdentifierIDLIETFIIFEIMAPImmutableIndexedDBInformation architectureInheritanceInk overflowInline-level contentInput method editorInstanceInternationalization (i18n)InternetInterpolationIntrinsic sizeIP AddressIPv4IPv6IRCISOISPITUJankJavaJavaScriptJPEGJSONJSON type representationKebab caseKeyKeywordLargest contentful paintLatencyLayout viewportLazy loadLGPLLigatureLiteralLocal scopeLocal variableLocaleLocalizationLong taskLoopLossless compressionLossy compressionLTR (Left To Right)Main AxisMain threadMarkupMathMLMediaMedia queryMetadataMethodMicrosoft EdgeMicrosoft Internet ExplorerMiddlewareMIMEMIME typeMinificationMitMMixinMobile FirstModemModularityMozilla FirefoxMutableMVCNamespaceNaNNATNativeNavigation directiveNetscape NavigatorNetwork throttlingNNTPNodeNode.jsNon-normativeNormativeNullNullish valueNumberObjectObject referenceOOPOpenGLOpenSSLOpera BrowserOperandOperatorOriginOTAOWASPP2PPACPacketPage load timePage predictionParameterParent objectParseParserPayload bodyPayload headerPDFPerceived performancePercent-encodingPHPPixelPlaceholder namesPlaintextPluginPNGPolyfillPolymorphismPOP3PortPrefetchPreflight requestPrerenderPrestoPrimitivePrivilegedPrivileged codeProgressive EnhancementProgressive web appsPromisePropertyProtocolPrototypePrototype-based programmingProxy serverPseudo-classPseudo-elementPseudocodePublic-key cryptographyPythonQuality valuesQuaternionQUICRAILRandom Number GeneratorRaster imageRDFReal User Monitoring (RUM)RecursionReflowRegular expressionRender-blockingRendering engineRepaintReplay attackRepoReporting directiveRepresentation headerRequest headerResource TimingResponse headerResponsive web designRESTRGBRILRobots.txtRound Trip Time (RTT)RoutersRSSRsyncRTCP (RTP Control Protocol)RTFRTL (Right to Left)RTP (Real-time Transport Protocol) and SRTP (Secure RTP)RTSP: Real-time streaming protocolRubySafeSame-origin policySCMScopeScreen readerScript-supporting elementScroll boundaryScroll chainingScroll containerSCTPSDK (Software Development Kit)SDPSearch engineSecond-level DomainSecure ContextSecure Sockets Layer (SSL)Selector (CSS)Self-Executing Anonymous FunctionSemanticsSEOSerializable objectSerializationServerServer TimingSession HijackingSGMLShadow treeShallow copyShimSignatureSIMDSimple headerSimple response headerSISDSiteSite mapSLDSloppy modeSlugSmoke TestSMPTE (Society of Motion Picture and Television Engineers)SMTPSnake caseSnap positionsSOAPSPA (Single-page application)SpecificationSpeculative parsingSpeed indexSQLSQL InjectionSRIStacking contextState machineStatementStatic methodStatic typingSticky activationStrict modeStringStringifierSTUNStyle originStylesheetSubmit buttonSVGSVNSymbolSymmetric-key cryptographySynchronousSyntaxSyntax errorSynthetic monitoringTable Grid BoxTable Wrapper BoxTagTCPTCP handshakeTCP slow startTelnetTexelThe Khronos GroupThreadThree jsTime to first byteTime to interactiveTLDTOFUTop layerTransient activationTransport Layer Security (TLS)Tree shakingTridentTruthyTTLTURNTypeType coercionType conversionUDP (User Datagram Protocol)UIUndefinedUnicodeUnix timeURIURLURNUsenetUser agentUTF-8UUIDUXValidatorValueVariableVendor PrefixViewportVisual ViewportVoid elementVoIPW3CWAIWCAGWeb performanceWeb serverWeb standardsWebAssemblyWebDAVWebExtensionsWebGLWebIDLWebKitWebMWebPWebRTCWebSocketsWebVTTWHATWGWhitespaceWindowProxyWorld Wide WebWrapperXForms
已弃用
XHTMLXIncludeXLinkXMLXMLHttpRequest (XHR)XPathXQueryXSLTZstandard compression
In this article参见UnicodeUnicode 是一种字符集标准,用于对来自世界上不同语言、文字系统和符号进行编号和字符定义。通过给每个字符分配一个编号,程序员可以创建字符编码,让计算机在同一个文件或程序中存储、处理和传输任何语言组合。
在 Unicode 定义之前,在同一数据中混合使用不同的语言是很困难的,而且容易出错。例如,一个字符集存储的是日文字符,而另一个字符集存储的是阿拉伯字母。如果没有明确标明数据的哪些部分属于哪个字符集,其他程序和计算机就会错误地显示文本,或者在处理过程中损坏文本。如果你曾经见过像 (“”) 被替换为胡言乱语 £,那么你就已经看到过这个被称为 Mojibake 的问题。
网络上最常见的 Unicode 字符编码是UTF-8。还存在一些其他编码,如 UTF-16 或过时的 UCS-2,但推荐使用 UTF-8。参见
Unicode on Wikipedia
The Unicode Standard: A Technical Introduction
Help improve MDNWas this page helpful to you?YesNoLearn how to contribute.This page was last modified on 2023年10月19日 by MDN contributors.View this page on GitHub • Report a problem with this contentMDN logoYour blueprint for a better internet.MDN on MastodonMDN on X (formerly Twitter)MDN on GitHubMDN Blog RSS FeedMDNAboutBlogCareersAdvertise with usSupportProduct helpReport an issueOur communitiesMDN CommunityMDN ForumMDN ChatDevelopersWeb TechnologiesLearn Web DevelopmentMDN PlusHacks BlogMozilla logoWebsite Privacy NoticeCookiesLegalCommunity Participation GuidelinesVisit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.Portions of this content are ©1998–2024 by individual mozilla.org contributors. Content available under a Creative Commons licen