字符编码笔记

最近对接人民银行征信系统,在生成数据报文的时候,文档要求「汉字信息交换按国家标准 GB2312-1980 和 GB18030-2000 执行」。什么意思呢?大白话来讲,就是要求我们在生成报文的时候,汉字编码要使用 GB2312 或 GB18030,GB2312 和 GBK 我常常用到,可这个 GB18030 却不太熟,所以查阅了一些资料来简单了解一下,不看不要紧,一看放不下了,干脆把相关的知识都梳理一遍吧 :)

字符编码的发展历程

ASCII

  1. ASCII 即 (American Standard Code for Information Interchange): 美国信息交换标准代码
  2. ASCII 码一共规定了 128 个字符的编码,比如空格 SPACE 是 32(二进制00100000),大写的字母 A 是 65(二进制01000001)。这 128 个符号(包括 32 个不能打印出来的控制符号),只占用了一个字节的后面 7 位,最前面的一位统一规定为 0。
  3. 对于英语而言,128 个字符似乎已经足够了,但是对于其他语言而言,这是不够滴。

ANSI

  1. 为了扩充 ASCII 编码以用于显示本国的语言,不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、Big5、Shift_JIS 等各自的编码标准。
  2. 这些使用 1 至 4 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码(貌似只有 windows 这样叫),又称为 MBCS(Muilti-Bytes Character Set,多字节字符集)。
  3. 在简体中文 Windows 操作系统中,ANSI 编码代表 GBK 编码;在日文 Windows 操作系统中,ANSI 编码代表 Shift_JIS 编码。不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
  4. 有关 ANSI 的更多内容,可以阅读 ANSI是什么编码?

Unicode

  1. 因为在世界上存在多种编码方式,因此,同一个二进制数字可以被解释成不同符号
  2. 我们每次只能用一种编码方式来打开文件,因而,不同编码方式编码的内容如果在同一文件中,打开时就会出现乱码
  3. 如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字所表示的,这是一种所有符号的编码。

UTF-8

  1. UTF-8 是在互联网上使用最广的一种 Unicode 的实现方式
  2. UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
  3. 扩展阅读:字符编码笔记:ASCII,Unicode 和 UTF-8

中文编码

中文编码字符集的国家标准中,先后出现并常见常用(截止 2020.02)的有 GB2312、GBK(严格讲,GBK 不是国家标准)、GB18030 ,下面分别简单介绍这三种中文编码标准。ps,点这里可以查询国家标准信息

GB2312

  1. GB 2312 或 GB 2312-80 或 GB 2312-1980 都是指中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,由中国国家标准总局 1980 年发布
  2. GB 2312 标准共收录 6763 个汉字;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个字符。
  3. GB 2312 的出现,基本满足了汉字的计算机处理需要,对于人名、古汉语等方面出现的罕用字,GB 2312 不能处理,这导致了后来 GBK 及 GB 18030 汉字字符集的出现。
  4. GB 2312 采用双字节编码

GBK

  1. GBK 即汉字内码扩展规范,K 为汉语拼音 Kuo Zhan(扩展)中「扩」字的声母。
  2. GBK 共收入 21886 个汉字和图形符号,包括:GB 2312 中的全部汉字、非汉字符号。
    BIG5 中的全部汉字(繁体字)。与 ISO 10646 相应的国家标准 GB 13000 中的其它 CJK 汉字,以上合计 20902 个汉字。其它汉字、部首、符号,共计 984 个。
  3. GBK 向下与 GB 2312 完全兼容,向上支持 ISO 10646 国际标准,在前者向后者过渡过程中起到的承上启下的作用。
  4. GBK 采用双字节编码

GB18030

  1. GB 18030,全称《信息技术 中文编码字符集》
  2. GB 18030 与 GB 2312-1980 和 GBK 兼容,共收录汉字 70244 个。
  3. 与 UTF-8 相同,GB 18030 采用多字节编码,每个字可以由 1 个、2 个或 4 个字节组成。
  4. 编码空间庞大,最多可定义 161 万个字符。支持中国国内少数民族的文字,不需要动用造字区。汉字收录范围包含繁体汉字以及日韩汉字

解决终端显示中文时出现乱码的问题

按要求,生成的报文中汉字编码采用 GB 18030,在代码中,只需对出现汉字的数据项使用函数转换编码方式即可

1
$name = iconv('UTF-8', 'GB18030', '一包小浣熊里七张卡');

当在终端使用 vim 或者 cat 命令查看生成的 txt 文件内容时,会出现乱码,所谓乱码就是使用了错误的编码方式来解读文件,下面是解决办法:

  1. 查看当前的字符编码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    zhangxi@mac ~ $ locale
    LANG="zh_CN.UTF-8"
    LC_COLLATE="zh_CN.UTF-8"
    LC_CTYPE="zh_CN.UTF-8"
    LC_MESSAGES="zh_CN.UTF-8"
    LC_MONETARY="zh_CN.UTF-8"
    LC_NUMERIC="zh_CN.UTF-8"
    LC_TIME="zh_CN.UTF-8"
    LC_ALL=
  2. 查找需要修改成的字符编码(注意 Mac OS 区分大小写)
    1
    2
    3
    4
    5
    6
    7
    zhangxi@mac ~ $ locale -a|grep zh_CN
    zh_CN.UTF-8
    zh_CN.GB2312
    zh_CN.GBK
    zh_CN.GB18030
    zh_CN
    zh_CN.eucCN
  3. 临时修改当前环境变量的字符编码,立刻生效
    1
    zhangxi@mac ~ $ export LANG=zh_CN.GB18030
  4. 查看是否生效
    1
    2
    3
    4
    5
    6
    7
    8
    9
    zhangxi@mac pbc $ locale
    LANG="zh_CN.GB18030"
    LC_COLLATE="zh_CN.GB18030"
    LC_CTYPE="zh_CN.GB18030"
    LC_MESSAGES="zh_CN.GB18030"
    LC_MONETARY="zh_CN.GB18030"
    LC_NUMERIC="zh_CN.GB18030"
    LC_TIME="zh_CN.GB18030"
    LC_ALL=
  5. 查看原来某个中文名的文件,发现乱码了,因为它之前是 UTF-8 编码的。但是使用 cat 输出文件内容,发现仍然也还是乱码的,需要进一步设置
  6. iTerm2->Preferences->Profiles->Terminal->Character encoding,选择如图的编码方式即可(经测试,选择 Simplified Chinese(Mac OS)/Simplified Chinese(Windows, DOS)/Simplified Chinese(GB 2312)也可)
  7. 再次使用 cat/vim 查看该文件,发现不再会出现乱码,大功告成!需要注意的是,刚才只是临时修改 linux 环境变量,下次登录会自动恢复,我们日常工作中也确实只是临时显示非 UTF-8 编码的中文,故而没有必要去真正的修改配置文件。但是终端软件的设置需要事后手动恢复为 UTF-8,否则你原来的中文文件名会显示乱码(该软件打开的任何 session 下)。