Mars's Blog

编码发展史

2022-01-14

阅读

相关术语

字符集:已编号的字符的有序集合(不一定连续)


字符码:字符集中每个字符的数字编号;如GBK采用区位码(矩阵的行号+列号),Unicode按照类别分到层面上。

​ 编码:字符转换为字节流

​ 解码:字节流解析为字符


字符编码:将字符集的字符码映射为字节流的一种实现方案

例如ASCII字符编码规定使用单字节中低位的7个比特去编码所有的字符。例如‘A’的编号是65,用单字节表示就是0x41,因此写入存储设备的时候就是b’01000001’。GBK编码则是将区位码(GBK的字符码)中的区码和位码的分别加上0xA0(160)的偏移(之所以要加上这样的偏移,主要是为了和ASCII码兼容),例如刚刚提到的“中”字,区位码是5448,十六进制是0x3630,区码和位码分别加上0xA0的偏移之后就得到0xD6D0,这就是“中”字的GBK编码结果。


代码页:字符编码的具体形式,用表格把字符直接映射为字节流,也就是字符 - 字节映射表。现代操作系统沿用了这种方式。


大小端:对于多字节,先写入高字节是大端(字节序和流设备的地址是相反的),先写入低字节是小端。二者是不同的字节存储顺序,叫字节序。(ps:字节序是从右往左,从低位到高位)

写文件和网络传输都是往流设备中写操作的过程,写操作是从流的低地址写往高地址(也就是内存的低地址到高地址,这样符合精神模型)

image-20220106101839715

编码发展历史

单字节编码

1byte,8bit


ASCII码

构建字符-数字对应关系

字符编码解码就是查表的过程


OEM字符集

ASCII定义的128个字符基础上,不同厂商对后面的128个字符建立了不同的对应关系


多字节字符集MBCS

一般根据第一个字节选择不同的码表解析


标准

标准化流程

ANSI编码:指的是平台的默认编码

只要操作系统预置标准字符集和平台专用字符集,就可以在该机器上阅读不同语言的文档


Unicode

涵盖了人类使用的所有字符,并且统一编号,一共有17层面* $2^{16}$个字符码空间

目前第0个已经涵盖了所有的字符,其他的用作扩展

包含的编码:

  • UCS-2/UTF-16:2个字节,而且ASCII经过UTF-16编码后,只占用低字节,高字节为0x00,C语言函数把这个视作字符串末尾而无法正确解析。
  • UTF-8:两个字节编码的存储和处理效率低,采用1-4个字节。
    • 带签名的UTF8:比较简单的方法是提取字节流前面的几个字符,检测是否符合字符编码的编码规则。但UTF8和ASCII对于纯英文是一样的,所以在字节流最前面加上BOM标记。
  • GB18030:我国,通过查表

编码系统的变化

Unicode出现之前

image-20220106113324832

缺点:字符和字节流耦合太重,难扩展。


Unicode的设计

image-20220106144001050

每个字符有Unicode码,唯一的。相当于加了一个中间键,然后根据具体的字符编码决定最终的字节序。


乱码问题

原因:错误字符编码去解码字节流

注意:遇到文本显示问题,时刻明确当前的字符编码。比如浏览器如果txt文本显示乱码,最好先检查当前浏览器的编码。


网页乱码问题的原因:

  • Response的Content-Type没有指明字符编码
  • 网页内是否使用META HTTP-EQUIV标签指定了字符编码
  • 网页文件本身存储时使用的字符编码和网页声明的字符编码是否一致

MySQL编码问题

已有表的编码调整:(会把表的编码和字段的编码同时调整)
1
alter table `tablename` convert to character set utf8;
global级别编码调整:(需要修改my.cnf)
1
2
3
4
5
6
7
[client]
default-character-set=utf8

# 在[mysqld]标签下,增加服务器端的字符编码
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

重启MySQL

1
~$ sudo /etc/init.d/mysql restart