字符编码详解

字符编码详解

     版本:v2.3.1

 

Crifan Li

摘要

本文主要介绍了字符编码的*础知识,以及常见的字符编码类型,比如ASCII,Unicode,UTF-8,ISO 8859等,以及各种编码之间的关系,同时专门解释了中文字符相关的编码标准,包括GB2312,GBK,GB18030,也专门解释了Windows系统中的Code Page,以及相关的BOM等内容

 

2.5. 代码页Code Page

2.5.1. 什么是代码页(Code Page)

Code Page,是字符编码的另一种说法。

Code Page包含了一个表,表中的值,用于表示针对某种语言所用的字符集。

更简单点说,就是Code Page中,用一个数字编号,表示了所要采用何种字符编码,去编解码相应的值,用于正确显示出相应的字符。

Code Page这一概念,源于IBM,后被其他常见广泛采用,包括Microsoft,SAP,Oracle等。

这些常见,各自定义了一套自己的Code Page,给每一个code page号,指定一个字符编码。

比如,对于众所周知的UTF-8编码,在IBM的Code Page中编号是1208,在微软中是65001,在SAP中是4110。

接下来,主要介绍大家最常见的Windows的Code Page

2.5.2. Windows中的Code Page

如前所述,Windows中也有自己的一套Code Page的定义。

用对应的某个数字,Code Page Number,即Code Page中的标识符(Identifier),表示相应的字符编码。

而一般Code Page也常缩写为CP

比如,CP936表示GBK中文编码,CP65001表示UTF-8编码,CP54936表示GB18030编码,CP950表示BIG5繁体中文等等。

[提示] C#中使用当前系统默认编码处理字符

对于C#来说,处理字符时涉及可能在不同环境中使用的话,那么最好用系统默认编码:

StreamReader reader = new StreamReader(path, System.Text.Encoding.Default);

2.5.2.1. Windows中的Code Page分类:ANSI和OEM

Windows中的Code Page,按照引用领域来划分,可以分为两类:ANSI Code Page和 OEM Code Page

2.5.2.1.1. Windows的ANSI Code Page表

ANSI Code Page的官网正式叫法其实是Windows Code Page。但是由于ANSI Code Page被误用的太广泛了,索性微软也就接受了此叫法,然后就叫做ANSI Code Page了。

类似地,ANSI Code Page=ANSI Windows Code Page

[提示] Windows的Code Page为何被误称为ANSI Code Page

Windows的Code Page中用的最广泛的是Windows 1252,其用于英语和西欧语言字符。

Windows 1252是*于ANSI草案(ANSI draft)而设计的。

结果,本来叫做Windows Code Page,就被很多不熟悉的人误读为ANSI Code Page

而实际上,(作为标准制定者的)ANSI和ISO,都从来没有去标准化Windows的Code Page,即没有为Windows Code Page指定过任何标准。

但是呢,由于ANSI Code Page被误用的太普遍了,导致微软官方也都承认此叫法了。

总之,记住一点,ANSI Code Page,就是Windows Code Page,就行了。

ANSI Code Page主要是用于Windows系统中,本地编码是非Unicode的,图形用户界面(GUI)程序。

ANSI的Code Page相关的表格,参见第 A.3.1.1 节 “ANSI Code Page表”

2.5.2.1.2. Windows的OEM Code Page表

OEM Code Page主要是用于Windows系统中的命令行界面(console)程序,虚拟DOS。

OEM Code Page可以视为是DOS和IBM PC时代的(过渡)剩余产品。

除了ANSI Code Page之外,之所以又设计出一个OEM Code Page,是因为:

  1. 兼容性

    因为作为新的图形用户界面系统的Windows,也要兼容旧的命令行程序,即向后兼容性。

  2. 字体和硬件的要求

    字体和旧的VGA硬件建议,文字图形界面所用的编码,最好和Code Page 437兼容。

    多数的OEM的Code Page,和(非ASCII的)后半部分的CP437,都是公用同一套代码点(code point)的。

    一般的OEM Code Page的后半段编码,和ANSI Code Page,完全不同。不过,对于部分双字节编码的,定长的Code Page(如泰语的847,越南语的1258)和多字节CJK编码的Code Page(如932,936,949,950)来说,ANSI和OEM的Code Page,都用的同一套编码。

和OEM Code Page相关的表格,参见第 A.3.1.2 节 “OEM Code Page表”

2.5.2.1.3. 一些常见的Code Page表

其中,ANSI和OEM共有的一些Code Page,可参见第 A.3.1.3 节 “ANSI和OEM共有的Code Page表”

而其他一些常见的Code Page,可参见第 A.3.1.4 节 “其他一些常见的Code Page表”

2.5.2.2. 所有的Code Page表

除了ANSI和OEM,以及ANSI,OEM共有的Code Page之外,其他还有很多Code Page定义。

关于所有的Windows中的Code Page的定义,可在微软官网[21]中找到。

此处已收录至第 A.3.2 节 “所有的Code Page相关的表格”,以方便查阅。

 

 

2.6. ANSI字符编码

2.6.1. ANSI是啥

ANSI,本身是American National Standards Institute的缩写,中文翻译为美国国家标准学会

ANSI是个非营利组织,其负责制定美国国家标准。

2.6.2. ANSI编码规则

ANSI字符编码的规则,或者是其所包含的字符的由来,主要是:

  1. 0-127 (0x00-0x7F)

    完全和7位编码的ASCII字符集(ASA X3.4-1963)相同

  2. 128-159 (0x80-0x9F)

    一些可打印字符

    这部分的编码,与国际编码ISO 8859-1的做法不同,ISO 8859-1是将此部分编码用于控制字符

  3. 160-255 (0xA0-0FF)

    参考了ISO 8859-1中的字符

由此可以看出,ANSI中很多字符,和ISO-8859中的字符,看起来非常相似。

这就导致了很多人误以为,ANSI和ISO-8859是一回事呢。

总结:

ANSI

= Windows Code Page 1252

= Windows Codepage 1252

= Windows 1252

= CP 1252

= 共256个字符

= 0-127的ASCII + 128-159的可打印字符 + 160-255的和ISO 8859-1中类似的字符

2.6.3. ANSI (Windows 1252)编码表

关于ANSI(Windows 1252)编码表格,可以参考:

[17]

[32]

2.6.4. ANSI编码与ANSI的关系

既然ANSI负责制定美国的国标,而在计算机方面,由于计算机最早是从美国最开始发展的,相应的所用到的字符编码方面,ANSI也制定了对应的标准,所以就叫做ANSI字符编码/ANSI字符集,英文为ANSI Code/ANSI Encoding/ANSI set/ANSI charset

2.6.5. ANSI字符编码和Windows 1252

Windows为了支持英语和西欧字符,自己设计了一个编码,对应的在Code Page号是1252,被称为Windows 1252。

Windows 1252的设计,是参考了ANSI草案(ANSI Draft)。

而ANSI draft后来发展成为正式的国际标准:ISO 8859-1

即,Windows 1252是在其成为正式标准ISO 8859-1之前而设计的,因此很容易理解,Windows 1252和ISO 8859-1不是完全等同的。

下面就来简要说说两者的区别。

2.6.5.1. Windows 1252和ISO 8859-1之间的区别

Windows 1252和ISO 8859-1*本等同

有点不同的是,在128-159(0x80-0x9F)的范围的值,ISO 8859-1编码为控制字符,而微软编码为可打印字符。

[提示] Windows 1252 vs. ANSI
  1. 类似Windows的Code Page为何被误称为ANSI Code Page,Windows 1252也被误称为ANSI编码,所以此处也可以说是ANSI编码和ISO 8859-1之间的区别。
  2. 而由于ISO 8859-1对应的Latin-1的西欧语言,所以此处也可以称为ANSI编码和ISO Latin-1之间的区别,比如[16]
  3. 微软的此种变体,有各种叫法:ANSI/Windows-1252/Windows Latin-1

    甚至有些微软的程序将其叫做Western European (Windows)。

    更有甚至,由于不清楚,而错称其为ASCII

[注意] 包含Lattin-1的内容在Notepad中显示乱码

因此,如果你把包含了128-159范围内的ISO Latin-1编码的文件,用Windows的记事本Notepad去另存为为ANSI的话,则会导致文件内容被错误处理了。

因为本身的那些128-159的字符,是控制字符,但是却被Notepad识别为可打印的字符了。

总之,对于Windows 1252,目前的各种叫法,可以理解为:

ANSI = Windows 1252 = CP 1252 = Windows code page 1252 = Windows Latin-1

2.6.6. 为何"ANSI编码"(在Windows中)被称为"本地编码"

先说一下本地编码,所谓本地编码,即当前Windows中的二进制的值,用何种编码去解析,然后显示出对应的该编码中的字符。

即,当然系统使用什么类型的编码。

而ANSI编码,根据前面内容得知,只是一个普通的对应于Windows 1252的一个编码而已。并不是其他某些编码合集的总称。

但是有时候,却又看到有人把ANSI编码解释为“本地编码”,比如[19]

其意思,就是[27]中所说的,Windows code pages有时又被称为"active code pages","system active code pages"。

而作为微软用A表示ANSI版本的函数,W表示Wide,Unicode版本的函数,此时所有的A版本的函数,就都用的是当前有效的Code Page,即"本地编码"了

其中,Windows系统中,当前有且只有一个active Windows code page。

也就意味着,此处所谓的ANSI编码,就相当于之前所说的Code Page了,即当前系统采用何种编码去解析字符

也就是你当前系统中设置的本地编码为何种编码,然后系统中,遇到需要解析的字符,就按照你所设置的本地编码去解析了。

比如,本身对于中文GBK编码的字符,如果你本地编码设置为UTF-8,那么按照UTF-8编码去解析出来的GBK字符,当前就是乱码了。

而只有正确设置为GBK,才能正确解析原本就是GBK编码后的字符,才能正确显示出中文。

同理,用GBK编码去解析原本用UTF-8编码后的字符,也会导致乱码。

[提示] 提示

这种乱码问题,常常会在和编码打交道的事情中遇到

比如Python中在命令行cmd中打印输出字符串,如果本身字符串是GBK编码的,那么你的cmd中的本地编码,就要设置为是936 (ANSI/OEM - Simplified Chinese GBK),这样中文字符才能正确显示。

当然,如果你本身输出的字符中,即包含UTF-8编码的字符,又包含GBK编码的字符,那么则是无论如何设置,都是无法同时正常显示的。除非你转换为Unicode编码,然后让Python输出函数自动处理,才可以正确显示。

 

 

2.8. 中文字符编码标准

2.8.1. GB2312,CP936,GBK,GB18030,GB13000

2.8.1.1. GB2312

1980年,中国制定了GB2312-80,一共收录了 7445 个字符,包括 6763 个汉字和 682 个其它符号。

GB2312-80,简称为GB2312。

在 Windows 中的代码页(Code Page)是 CP936。

2.8.1.2. GB13000

1993年,国际标准Unicode 1.1版本推出,收录中国大陆、台湾、日本及韩国通用字符集的汉字,总共有20,902个。

中国大陆订定了等同于Unicode 1.1版本的“GB 13000.1-93”,简称为GB13000。

GB13000,显然包含的GB2312已有的文字和其他很多为包含的文字,如GB 2312-80推出以后才简化的汉字(如“啰”),部分人名用字(如中国前总理***的“*”字),台湾及香港使用的繁体字,日语及朝鲜语汉字等。

2.8.1.3. GBK

微软,对GB2312-80的扩展,即利用GB 2312-80未使用的编码空间,收录所有的GB 13000.1-93和Unicode 1.1之中的汉字全部字符,制定了GBK编码。

GBK 收录了 21886 个符号,它分为汉字区和图形符号区。汉字区包括 21003 个字符。

GBK 作为对 GB2312 的扩展,在现在的 Windows 系统中仍然使用代码页 CP936 表示,但是同样的 936 的代码页跟一开始的 936 的代码页只支持 GB2312 编码不同,现在的 936 代码页支持 GBK 的编码,GBK 同时也向下兼容GB2312 编码。

所以,技术编码上,GBK兼容旧的GB2312,但是编码方式和GB13000不同,不兼容GB13000,但是所包含文字上,算是和GB13000相同。

2.8.1.4. GB18030

GBK自身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为“技术规范指导性文件”。

原始GB13000一直未被业界采用,2000年,国家出了标准GB18030-2000,简称GB18030,技术上兼容GBK而非GB13000,取代了 GBK1.0,成了正式的国家标准

该标准收录了 27484 个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。

现在的PC平台必须支持 GB18030 ,对嵌入式产品暂不作要求。所以手机、MP3 一般只支持 GB2312。

GB18030 在 Windows 中的代码页是 CP54936。

这么多汉字编码标准的关系,总结起来就是第 2.8.2 节 “各种中文字符编码标准的关系”中所介绍的。

2.8.2. 各种中文字符编码标准的关系

( 中国大陆的标准)GB 13000.1-93

=(国际标准)Unicode 1.1

 

(中国大陆标准)GB2312-80

= 简称GB2312

= Windows系统中的原先的CP936

 

(微软制定的)GBK

= (微软在编码方面)对 GB2312 的扩展

= (微软在所包含字符方面上包含了)GB 13000.1-93 + 其他部分汉字+ 台湾和香港的繁体 + 日语 + 朝鲜汉字

= Unicode 1.1 + 其他部分汉字+ 台湾和香港的繁体 + 日语 + 朝鲜汉字

对于GBK

  • 在编码方面:向下兼容GB2312,但是和GB 13000不同
  • 在内容方面:等价于GB13000

 

微软中现在的新的CP936

= GBK

=兼容旧的GB2312

 

在技术编码方面上,演化顺序为:

ASCII ⇒ GB2312 ⇒ GBK ⇒ GB18030

后者对之前的,都是支持之前的编码,即向下兼容,即同一个字符,在这些编码中,都是同样的值,后面的标准,支持更多的字符。

区分中文编码的方法是高字节的最高位不为 0。

按照程序员的称呼,GB2312、GBK 到 GB18030 都属于双字节字符集 (DBCS)

表 2.5. 中文字符相关编码标准

编码标准别名标准所属包含字符
ASCII   国际通用  
GB2312 微软Windows中以前的CP936 中国大陆 6763 个汉字和 682 个其它符号
Unicode 1.1   国际通用 20,902个字符
GB13000   中国大陆 20,902个字符
GBK 微软Windows中现在的CP936 微软 21886 个符号
GB18030 微软Windows中的CP54936 中国大陆 27484 个汉字+其他少数民族字符

 

 

posted @ 2021-05-21 12:48  ChuckLu  阅读(1023)  评论(0编辑  收藏  举报