Rexdf

The devil is in the Details.

编码小记

| Comments

偶尔我们会想获取汉字的编码,然而似乎网上随手一搜,在线转换工具倒是有不少只是好像都不太能满足真实需求。

也许你会想到notepad++按照编码保存,然后用二进制打开。当然这在Windows下不失为不错的办法。

鉴于UTF-8推荐的越来越多,我就来列举下它对于中文来说的缺点。

顺便也说说对于汉字,UTF-8其实并不适合保存。虽然因为现在互联网应用交换的绝大部分都是html/css/js的原因,utf-8格式大行其道。但是对于中国的常规应用来说,其实不需要用UTF-8表示。

简单点说:对于一个以英语为主,偶尔会需要显示一两个汉字,那么utf-8优势巨大。对于基本上是汉字,只需要偶尔显示一两个英文缩写的应用。GBK或者UTF-16优势巨大。

原因在于汉字、日语都被UTF-8都被编码到了三字节,然而其中的有效位只有两字节,剩下一字节是用来做标志位的。也就是每个汉字要多浪费一个字节。而且UTF-8是变长编码,从1到4都会出现,对于字符串函数实际上很不方便。当然对于库函数丰富的今天这不算大问题,只是进行了一次内码转换而已。 而且3字节的汉字,中间夹杂着1字节的ASCII字符,这种编码在内存中处理,实际上非常麻烦的,不停要做移位操作,连简单的字符个数都是O(n)的。

好了批判完了,写点有用的。

编码获取

我的方法是用Python,简单轻量级。

十六进制

>>> import binascii
>>> binascii.hexlify('我们'.encode('utf-16le'))
b'1162ec4e'

十进制

这是是给 ALT + 数字 这种输入法用的。 需要注意的是,这里要用大端。

>>> int.from_bytes('我'.encode('gbk')[:2],'big')
52946

中文Windows下面按住Alt键,快速输入52946,就会出现汉字.

测试编码

我们来测试下本文的markdown,上面的文本。

>>> s='''...'''
>>> len(binascii.hexlify(s.encode('utf-16le')))
2716
>>> len(binascii.hexlify(s.encode('utf-8')))
3094

0xfffe是BOM,可以发现UTF-8对常见汉字编码确实要多一个字节的。

>>> binascii.hexlify('我们'.encode('utf-16'))
b'fffe1162ec4e'
>>> binascii.hexlify('我们'.encode('utf-16le'))
b'1162ec4e'
>>> binascii.hexlify('我们'.encode('gbk'))
b'ced2c3c7'
>>> binascii.hexlify('我们'.encode('gb18030'))
b'ced2c3c7'
>>> binascii.hexlify('我们'.encode('utf-8'))
b'e68891e4bbac'

一些资料整理

汉字的国标

编码 生效日期 备注 编码范围
GB2312 1981.5.1 GB2312编码共收录汉字6763个,其中一级汉字3755个,二级汉字3008个。同时,GB2312编码收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。 A1A1-FEFE(41377-65278)其中汉字编码范围:B0A1-F7FE(45217-63486)。
GBK 1995.12.15 GBK编码,是对GB2312编码的扩展,因此完全兼容GB2312-80标准。GBK编码依然采用双字节编码方案,其编码范围:8140-FEFE,剔除xx7F码位,共23940个码位。共收录汉字和图形符号21886个,其中汉字(包括部首和构件)21003个,图形符号883个。 8140-FEFE (33088-65278)
GB18030-2000 2000.3.17 是对GBK编码的扩充,覆盖中文、日文、朝鲜语和中国少数民族文字,其中收录27484个汉字。GB18030字符集采用单字节、双字节和四字节三种方式对字符编码。兼容GBK和GB2312字符集。 采用单字节、双字节、四字节分段编码方案,具体码位见特性。GB18030向下兼容ASCII码和GBK编码。
GB18030-2005 . 最主要的变化是增加了CJK统一汉字扩充B。它还去掉了单字节编码的欧元符号0x80)。GB18030有1611668个码位,在GB18030-2005中定义了76556个字符。 .

GBK 的代码页是936,GBK18030的代码页是54936.

一些编码常识

ANSI

Windows记事本的ANSI编码

ANSI (American National Standards Institute) 美国国家标准学会的缩写。 在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在繁体中文操作系统中,ANSI编码代表Big5编码;在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。

Unicode UTF-8 UTF-16 UCS-2

关于Unicode与UTF-8 UTF-16 UCS-2的关系

Unicode(统一码、万国码、单一码、标准万国码)编码就是为表达任意语言的任意字符而设计。特点: 一个字符代表一个code,不存在二义性,而且这套标准也会随着需求不断的拓展。由非盈利机构 The Unicode Consortium 负责,官网为 http://www.unicode.org/

Unicode是一个标准,只规定了某个字符应该对应哪一个code,但是并没有规定这个字符应该用即为字节来存储。规定用几个字节存储字符的是Unicode的不同实现,譬如UTF-8,UTF-16, UTF-32等。

所以 UTF-8 UTF-16 的编码范围都是全部的Unicode字符集的。

UTF-8是采用变长的编码方式,为1~6个字节,但通常我们只把它看作单字节或三字节的实现,因为其它情况实在少见。。

Unicode编码中,最常用的字符其实是0-65535,因此针对这点产生了UTF-16方案。 UTF-16将0–65535范围内的字符编码成2个字节,超过这个的用4个字节编码。(因此基本可以认为是双字节的) UTF-16是完全对应于UCS-2的,即把UCS-2规定的代码点通过Big Endian或Little Endian方式直接保存下来。所以UTF-16采用2个字节来存储Unicode。UTF-16也可以表示UCS-4的部分字符,所以UTF-16也采用4个字节来存储Unicode。 UTF16编码是Unicode最直接的实现方式,通常我们在windows上新建文本文件后保存为Unicode编码,其实就是保存为UTF16编码。

BIG5 Shift-JIS

其他汉字编码BIG5 Shift-JIS

BIG5编码又称大五码,是繁体中文字符集编码标准,共收录13060个中文字,其中有二字为重复编码。BIG5重复地收录了两个相同的字:“兀、兀”(A461及C94A)、“嗀、嗀”(DCD1及DDFC)。编码范围8140-FEFE(33088-65278) 其中汉字编码范围:A440-F9DC(42048-63964) BIG5采用双字节编码,使用两个字节来表示一个字符。高位字节使用了0x81-0xFE,低位字节使用了0x40-0x7E,及0xA1-0xFE

Shift-Jis比较特殊,不连续,需要校验合法性,而且有特殊的转换公式与技巧,有时会在代码中看到。

ASCII字符 (0x20-0x7E),但“\”被“¥”取代 ASCII控制字符(0x00-0x1F、0x7F) JIS X 0201标准内的半角标点及片假名(0xA1-0xDF) 在部分操作系统中,0xA0用来放置“不换行空格”。

以下字符在Shift_JIS使用两个字节来表示。

  • JIS X 0208字集的所有字符

“第一位字节”使用0x81-0x9F、0xE0-0xEF(共47个) “第二位字节”使用0x40-0x7E、0x80-0xFC(共188个)

  • 使用者定义区

“第一位字节”使用0xF0-0xFC(共13个) “第二位字节”使用0x40-0x7E、0x80-0xFC(共188个)

在Shift_JIS编码表中,并未使用0xFD、0xFE及0xFF。

在微软及IBM的日语电脑系统中,在0xFA、0xFB及0xFC的两字节区域,加入了388个JIS X 0208没有收录的符号和汉字。

Comments