欢迎光临散文网 会员登陆 & 注册

【编码】GB编码的一些零碎

2023-04-29 13:29 作者:冒-_-泡  | 我要投稿

前文提到,ISO646规定的7-bit ASCII标准并不能适应所有语言,在当时那个条件下,标准提供了若干可替代字符的变种方案,例如上篇说到的德文编码DIN。然而这是一个有损的方案,典型表现之一就是催化出了C语言代用记号这种东西,而且世界上的文字不止英文,即便只看欧洲的拉丁文字符集,替代字符的做法也只能算是扬汤止沸

幸好就ASCII来说,7-bit的范围已经足够大了,而一个字节是8-bit,这就给其他语言文字留了设计思路的空间。在unicode普及之前,甚至unicode发布之前,如何用字节序列来表示一个超出128大小的字符序列就是各种编码需要研究的问题,当然,如果能用多字节来表示一个字符,那这就不是一个问题,实际工程问题是需要兼容ASCII,且做到空间占用尽可能短

一个字节8-bit进入ISO的时间相对较晚(印象中是2008年),但在此之前已经在很长时间里成为主流实现了

很多人都是win系统入门计算机的,所有编码相关的知识很多也来自于中文windows

最早学计算机的时候,我接触到的中文编码是GB2312,其中GB是国标的意思,意即国家标准的中文编码,由此衍生的还有输入法中的区位码(大概很多人都没听过了)

GB2312兼容ASCII,采用两个值>=128的字节表示一个汉字,也就是说,它是一个变长编码,解析原则是:

  • 如果一个字节在0~127,那么表示一个普通ASCII字符

  • 如果一个字节在128~255,那么继续读下一个字符(且下一个字符是128~255),两个字符联合起来的值代表一个汉字(也包括拉丁字母、日文、标点符号的全角字符等,这些字符数量和汉字比起来是九牛一毛,就囊括了)

GB2312包含了7573个字符,用下面的代码很容易测试出来(Python3):

除去兼容的ASCII以及上面提及的全角字符外,汉字大约收录了6000多个

这个数量,熟悉汉字的中国人一看就知道不行,最简单的,当年高考录入名字的时候,很多冷僻字都没法输入

所以后面扩展了标准,推出了GBK,这里的K是指扩展的意思,GBK将字符数扩充至21919个字符,也成了当年windows下中文的标准字符编码,又名cp936,cp是code page的意思,相当于GBK在编码规范中的文件编号

以前很多人将GBK称为ANSI编码,在python中用ANSI也的确能encode,而且在中文win下测试,字符集和GBK差不太多,不过ANSI是美国国家标准委员会的意思,并不是直接指代GBK,或者说它和系统是相关的编码集,且字符集还是有差异的,所以“ANSI编码”这个说法并不适合

GBK在编码上沿袭了GB2312的做法,兼容ASCII,用双字节表示中文,但是从字符数量我们很容易看出,它不可能遵循“双字节都是128~255”这一规范,因为这个范围只有128,双字节能表示的则是128×128=16384个字符,不可能在20000+的数量

所以,既要兼容ASCII,又要限定非ASCII字符是双字节,那只能在第二个字节做妥协了,也就是说,GBK中的相当多的非ASCII字符,是第一个字符128~255,而第二个字符是0~127的,而我们知道很多文本处理是把文件当字节序列来看待,这就可能出现一些问题

例如我在腾讯碰到过的一个日志处理问题(因为历史原因,某些老系统用的是GBK编码):

这是一个用竖线分隔字段的日志文件,我们用Python2来解析:

这里出现了异常,原因是:

“珅”这个字在GBK编码中,第二个字符是竖线,干扰了日志格式

当然,双字节的第二个字节是0~127的,一般也都是比较生僻的汉字,但它们很多时候会出现在姓名中,在文本处理上会出现麻烦

要避免类似的问题,统一用utf8就好了,为什么utf8可以规避类似问题呢,看看utf8的编码规定就知道了:

可以看到,作为一种多字节变长编码,utf8通过每个字节的前缀bit严格区分了它们的作用:

  • 高位是0的,为单字节的ASCII字符

  • 高位10的,是多字节序列中的后续字节

  • 高位是11开头的,是多字节序列的首字节

这些规定不但使得不同字符的编码字节不会互相混淆,也确定了多字节序列的边界,抗乱码能力也非常强,丢失单字节是不会造成乱码的,很容易纠错,只有丢失了连续多个字节的时候,才可能出现错误内容


【编码】GB编码的一些零碎的评论 (共 条)

分享到微博请遵守国家法律