计算机字符编码

1、ASCII编码

  • ASCII (American Standard Code for Information Interchange):美国信息交换标准代码
  • 计算机起源于美国,上个世纪,他们对英语字符与二进制位之间的关系做了统一规定,并制定了一套字符编码规则,这套编码规则被称为ASCII编码
  • ASCII 编码一共定义了128个字符的编码规则,用七位二进制表示 ( 0x00 - 0x7F ), 这些字符组成的集合就叫做 ASCII 字符集

2、字符集和字符编码

字符集

随着计算机的普及,在不同的地区和国家又出现了很多字符编码,比如: 大陆的 GB2312、港台的 BIG5, 日本的 Shift JIS等等。由于字符编码不同,计算机在不同国家之间的交流变得很困难,经常会出现乱码的问题,比如:对于同一个二进制数据,不同的编码会解析出不同的字符。当互联网迅猛发展,地域限制打破之后,人们迫切的希望有一种统一的规则, 对所有国家和地区的字符进行编码,于是 Unicode 就出现了。
Unicode 是国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。Unicode 字符集的编码范围是 0x0000 - 0x10FFFF , 需要 1-3 个字节,可以容纳一百多万个字符, 每个字符都有一个独一无二的编码,也即每个字符都有一个二进制数值和它对应,这里的二进制数值也叫码点 , 比如:汉字 “中” 的 码点是 0x4E2D, 大写字母 A 的码点是 0x41, 具体字符对应的 Unicode 编码可以参考以下链接:https://www.unicodery.com/block/
字符集是很多个字符的集合,例如 GB2312 是简体中文的字符集,它收录了六千多个常用的简体汉字及一些符号,数字,拼音等字符
字符编码是 字符集的一种实现方式,把字符集中的字符映射为特定的字节或字节序列,它是一种规则
Unicode 只是字符集,UTF-8、UTF-16、UTF-32 才是真正的字符编码规则

字符编码

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 个字节来存储

3、UTF-8编码

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 码,从低位开始填充,不够的补0
  • 举例:中
    • Unicide码:0x4E2D 16位
    • UTF-8:0xE4B8AD 24位(规则要占用8位,加16位Unicode,共24位,刚好满足)
 "中" 字的 Unicode 码 0x4E2D, 2个字节,16位二进制,表示如下:
0100 1110 0010 1101

Unicode字符集“中”已经占据2个字节,如果采用UTF-8字符编码,肯定要额外添加字节来存储其他数据,这里我们暂定用3个字节24位来存储,按照上面的规则:
第一个字节:1110 xxxx
第二个字节:10xx xxxx
第三个字节:10xx xxxx
UTF-8编码规则用掉了8位,总共24位,还有16位可用(16个x),刚好用来存储Unicode字符集的16位码点0x4E2D,综上"中"用utf8编码显示如下
1110 0100 1011 1000 1010 1101  = 0xe4 b8 ad	

  • 举例:𠠠
    • Unicide码:0x20820 20位
    • UTF-8:0xF0A0A0A0 32位(规则要占用11位,加20位Unicode,共31位,满足)
𠠠 Unicode码占用200x20820
0010 0000 1000 0010 0000
3个字节来存储,就不够了,需要4个字节来存储
第一个字节:1111 0xxx
第二个字节:10xx xxxx
第三个字节:10xx xxxx
第四个字节:10xx xxxx

只用了低位的20位,左起第6位的0是默认补的
1111 0000 1010 0000 1010 000 1010 0000

UTF8F0 A0 A0 A0

UTF8各字节编码范围

  • UTF-8编码最短的为一个字节、最长的目前为四个字节,从首字节就可以判断一个UTF-8编码有几个字节:
    • 如果首字节以0开头,肯定是单字节编码(即单个单字节码元);
    • 如果首字节以110开头,肯定是双字节编码(即由两个单字节码元所组成的双码元序列);
    • 如果首字节以1110开头,肯定是三字节编码(即由三个单字节码元所组成的三码元序列),以此类推。

  • 单字节,UTF8编码占据1位,剩下的7位可以存储,可编码的Unicode码点值范围十六进制为0x0000 ~ 0x007F,十进制为0 ~ 127;
  • 双字节,UTF8编码占据5位,剩下的11位可以存储,可编码的Unicode码点值范围十六进制为0x0080 ~ 0x07FF,十进制为128 ~ 2047;
  • 三字节,UTF8编码占据8位,剩下的16位可以存储,可编码的Unicode码点值范围十六进制为0x0800 ~ 0xFFFF,十进制为2048 ~ 65535;
  • 四字节,UTF8编码占据11位,剩下的21位可以存储,可编码的Unicode码点值范围十六进制为0x10000 ~ 0x1FFFFF,十进制为65536 ~ 2097151
  • Unicode 字符集的编码范围是 0x0000 - 0x10FFFF,UTF8最大到0x1FFFFF,UTF8能完全覆盖Unicode字符

常用字符范围

  • 汉字的UTF8编码范围:[0x4e00,0x9fa5](或十进制[19968,40869])
  • 数字:[0x30,0x39](或十进制[48, 57])
  • 小写字母:[0x61,0x7a](或十进制[97, 122])
  • 大写字母:[0x41,0x5a](或十进制[65, 90]

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 编码
  • 举例:𐩯
    • Unicide码:0x10A6F 20位,需要用四个字节存储
    • UTF-16:0xD802DE6F 32位(规则要占用12位,加20位Unicode,共32位,满足)
𠠠 Unicode码占用200x10A6F
0001 0000-1010 0110-1111
减去0x10000 等于0xA6F
0000 0000-1010 0110-1111

UTF-16编码固定如下:1101-10xx  xxxx-xxxx  1101-11xx xxxx-xxxx
UTF-16编码的2进制:1101-1000 0000-0010 1101-1110 0110-1111
UTF-16编码的16进制:D8 02 DE 6F

5、UTF-32 编码

  • UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 码即可,不需要任何编码转换。虽然浪费了空间,但提高了效率。

6、UTF 字节序

  • 最小编码单元是多字节才会有字节序的问题存在,UTF-8 最小编码单元是一字节,所以 它是没有字节序的问题,UTF-16 最小编码单元是 2 个字节,在解析一个 UTF-16 字符之前,需要知道每个编码单元的字节序
  • 比如:前面提到过,“中” 字的 Unicode 码是 4E2D, “ⵎ” 字符的 Unicode 码是 2D4E, 当我们收到一个 UTF-16 字节流 4E2D 时,计算机如何识别它表示的是字符 “中” 还是 字符 “ⵎ” 呢 ?
  • 所以,对于多字节的编码单元,需要有一个标记显式的告诉计算机,按照什么样的顺序解析字符,也就是字节序,字节序分为 大端字节序 和 小端字节序
  • 小端字节序简写为 LE( Little-Endian ), 表示 低位字节在前,高位字节在后, 高位字节保存在内存的高地址端,而低位字节保存在内存的低地址端
  • 大端字节序简写为 BE( Big-Endian ), 表示 高位字节在前,低位字节在后,高位字节保存在内存的低地址端,低位字节保存在在内存的高地址端

  • 数据是从高位字节到低位字节显示的,这也更符合人们阅读数据的习惯,而内存地址是从低地址向高地址增加
  • 所以,字符0x4E2D 数据的高位字节是 4E,低位字节是 2D
  • 按照大端字节序的高位字节保存内存低地址端的规则,4E 保存到低内存地址 0x10001 上,2D 则保存到高内存地址 0x10002 上
  • 对于小端字节序,则正好相反,数据的高位字节保存到内存的高地址端,低位字节保存到内存低地址端的,所以 4E 保存到高内存地址 0x10002 上,2D 则保存到低内存地址 0x10001 上

7、BOM

  • BOM 是 byte-order mark 的缩写,是 “字节序标记” 的意思。BOM是用来判断文本文件是哪一种Unicode编码的标记,其本身是一个Unicode字符(“\uFEFF”),位于文本文件头部。
  • 在不同的Unicode编码中,对应的bom的二进制字节如下,所以我们可以根据文件头部的几个字节和上面的表格对应来判断该文件是哪种编码形式。
    • UTF16BE的BOM:FE FF 对应十进制:254 255
    • UTF16LE的BOM:FF FE 对应十进制:254 255
    • UTF8的BOM:EF BB BF 对应十进制:239 187 191
    • UTF-32 (big-endian):00 00 FE FF:
    • UTF-32 (little-endian):FF FE 00 00
  • UTF-8 没有字节序问题,上述字符只是用来标识它是 UTF-8 文件,而不是用来说明字节顺序的。“零宽度非换行空格” 字符 的 UTF-8 编码是 EF BB BF, 所以如果接收到以 EF BB BF 开头的字节流,就知道这是UTF-8 文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码充电宝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值