关于编码格式的总结

来源:互联网 发布:nginx lua redis 安装 编辑:程序博客网 时间:2024/05/17 01:23

最近在用Java做文本处理的时候,经常遇到一些乱码的问题,因此决定好好看一下编码格式的问题。所谓编码,从我的理解就是一种映射关系,即数字到符号的一一映射;而编码标准就是那张映射表,它决定了哪一个数字对应了哪一个符号,在计算机的世界里面实际是只有数字的,但是标准的存在则是数字与符号联系的纽带。现在常用的编码主要有以下几种:ASCII、Unicode、UTF-8(有无BOM)、UTF-16、UTF-32、GBK等。

ASCII

ASCII是指美国标准信息交换代码,是基于拉丁字母的一套电脑编码系统,是现今最通用的单字节编码系统。ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符,而我们常用的其实是使用指定7位二进制数组合来表示128种字符的标准ASCII

在标准ASCII中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展(或“高”)ASCII。扩展ASCII 码允许将每个字符的第8 位用于确定附加的128 个特殊符号字符、外来语字母和图形符号。

对于英语来说,标准ASCII几乎涵盖了所有的字符,因而对于只使用英文字符和数字的情况,采用ASCII编码就完全足够。但对于其他语言,128字符是完全不够的,比如常用的中文汉子就有几千个,更不提全世界所有的语言字符加起来的和,所以一种通用的编码方式就产生了。

Unicode

Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。Unicode用0~0x10FFFF(使用21位二进制数即可表示完全)来映射这些字符,最多可容纳1114112个字符(17*65536,17表示0~0x10共17个数字)。

通用字符集(Universal Character Set, UCS)是由ISO制定的ISO 10646标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。UCS-4根据最高位为0的最高字节分成2^7=128个group,每个group再根据次高字节分为256个平面(plane),Unicode计划使用了17个平面,一共有17×65536=1114112个码位。group 0的平面0被称作BMP(Basic Multilingual Plane)。如果UCS-4的前两个字节为全零,那么将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。所以其实UCS-2只能表示Unicode中在0~0xFFFF内的字符,其中中文的范围为4E00~9FBF,共定义了27973个汉字。除此之外,平面2上还定义了43253个汉字。

Java中基本数据类型char采用的就是Unicode编码,确切说应该是UCS-2,即使用两个字节来表示一个字符,所以Java中char类型能表示的字符范围为0~0xFFFF,超过这个范围的Unicode编码实际上char是表示不了的,即char只能表示Unicode的BMP平面的字符

UTF-8

UTF-8以字节为单位对Unicode进行编码,其特点是对不同范围的字符使用不同长度(1~6字节)的编码。对于0x00~0x7F之间的字符,UTF-8编码与标准的ASCII编码完全相同,即向下兼容标准ASCII编码。如果文本中全是英文字符,那么采用ASCII编码读写与采用UTF-8编码读写都是可以的。其具体编码方式如下:

Unicode编码(16进制) UTF-8 字节流(二进制) 00000000 - 0000007F 0xxxxxxx 00000080 - 000007FF 110xxxxx 10xxxxxx 00000800 - 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx 00010000 - 001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 00200000 - 03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 04000000 - 7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

我们常常也会看到UTF-8带BOM,这里的BOM其实是用来区分字节序的。字节序有两种,分别为“大端”(Big Endian,BE)和“小端”(Little Endian,LE)。对于BE,内存在载入数据时先将高序字节存储在起始地址,再存入低序字节,而LE恰恰相反。Unicode标准建议传输字节流前,先传输被作为BOM的字符来判别该字节流采用的是哪种编码方式,这些字符在Unicode中都是未定义的码位,不应该出现在实际传输的内容中。

UTF编码 Byte Order Mark (BOM) UTF-8 without BOM 无 UTF-8 with BOM EF BB BF UTF-16LE FF FE UTF-16BE FE FF UTF-32LE FF FE 00 00 UTF-32BE 00 00 FE FF

UTF-8其实不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM,不含 BOM 的 UTF-8 才是标准形式。在 UTF-8 文件中放置 BOM 主要是微软的习惯,微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。如果我们接收到以EF BB BF开头的字节流,就知道这是采用的UTF-8编码了。无BOM的UTF-8使用的其实更广,所以一般情况下尽量用无BOM的形式

UTF-16

UTF-16编码以16位无符号整数为单位。我们把Unicode编码记作U。编码规则如下:如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(两个字节);如果U≥0x10000,我们先计算U’=U-0x10000,然后将U’写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx(四个字节)。

为了将两字节的UTF-16编码与四字节的UTF-16编码区分开来,Unicode编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate)。计算机读取两个字节的数据后,发现如果这两个字节在0xDB00~0xDBFF,那么这个字符必定采用的是四字节进行编码,其后两个字节的范围必定在0xDC00~0xDFFF之间。如果我们处理的文本没有在0xDB00~0xDBFF范围内的字符,那么采用UTF-16编码与采用UCS-2编码是没有区别的(不考虑BOM,只考虑数值)。Java中的String采用的就是UTF-16编码

UTF-32

UTF-32编码以32位无符号整数为单位。Unicode的UTF-32编码就是其对应的32位无符号整数,与UCS-4一致。

GBK

GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification),完全局限于汉字编码 。GBK编码,是在GB2312-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准,支持国际标准ISO/IEC10646-1(即UCS)和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。

1 0
原创粉丝点击