编码格式

从字符编码的发展历史理解ANSI、GB2312、Unicode、UTF8和UTF16区别

 在编程学习的深入后,不可避免的会遇到ANSI、GB2312、UTF8的编码问题,如果不彻底了解他们的区别,都最终会造成一个问题--乱码!例如文件打开乱码,数据库乱码、网页乱码等等各种乱码,这里就通过字符编码发展历史的介绍来分清各种不同的编码。

一、ASCII码

        我们都知道计算机起源于美国,早期的计算机只是用于科学计算,但是在计算机迅速发展时,计算机被要求不仅仅能够进行数值计算,还要进行字符处理和表示。于是一套名为ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)码的编码方式被创造而出,使用7位(bit)来表示一个字符,总共能够表示128种字符。

        这套编码包含了控制码(例如\n换行符等)、符号(?!等)、数字和26个英文字母包括其大小写。但是由于这是一套由美国人提出的美国字符编码所以并没有包含中文、韩文等等其他国家的语言,毕竟当时谁也没想到计算机会普及到全世界。

后来IBM对这套ASCII码进行了扩充,使用8位来表示一个字符,新增了128种字符,这也仅仅是对一些拉丁字母和特殊符号的扩充。

二、ANSI

        当计算机普及到全世界时,各个国家面临的首要问题就是要针对自己国家的语言制定一套自己国家的编码规范,我国就提出里一套针对中文的GB2312的编码方式,这套编码方式基于ASCII码(并非IBM的ASCII扩充版本),使用2个字节表示一个汉字,具体的方式是前127个字符不变。当第一个字节(高字节)大于160的时候,表示一个汉字的开始,再用这个字节组合第二个字节(低字节,范围也是160-255)共同表示一个汉字。在这套编码方式中,不仅把中文编码进去,还把一些数学符号、罗马希腊字母和日本假名等等都编码进去,并且还把ASCII中原有的26个英文字母和符号都编入,当然这些字母是以2个字节表示,为和ASCII中原有的字母区别表示,称前者为“全角字符”,后者为“半角字符”。

        当然我大中华文化底蕴深厚,GB2312也只能编入部分常用汉字,为了把更多的汉字编入进来,针对GB2312进行扩充,就创造出了GBK标准。GBK只要求当高字节大于127时就表示汉字的开始,低字节也不再要求范围。

        类似我国的编码方案,其他地区和国家也制定了自己的编码方案,如日本的Shift_JIS等等。这些编码方案称为 "DBCS"(Double Byte Charecter Set 双字节字符集)"即是用双字节表示一个字符,也称为ANSI。这里的ANSI代表了不同国家的不同编码方案,如果一台Windows操作系统设定为中文,那么ANSI就表示GBK,如果设定为日本ANSI就表示Shift_JIS。ANSI虽然能够表示全世界的字符,但是产生两个比较麻烦的问题。

1、一段使用ANSI编码的字符串,有中文有英文,如何统计共有多少字符?这下麻烦了,如果是单纯的英文,sizeof一下即可,但是有中文混杂其中则必须便利一遍并做判断,十分麻烦

2、也是最麻烦的一个问题,使用ANSI编码的一篇文章,被台湾友人拿去,打开后,全是乱码,因为台湾地区使用的是BIG5码,不同的地区编码虽然都称作ANSI,但是互相之间没有算法做出转换,这大大影响了阻碍各地区、国家之间的交流

(中文编码详细内容请查看我的博客【中文编码-区位码、国标码、内码区别】)

三、Unicode

        为了统一全世界的文字编码,ISO(国际标准化组织)制定了一种新的编码规范,这种编码规范将全世界的文字放在一张表内,称它为"Universal Multiple-Octet Coded Character Set",简称 UCS, 俗称"UNICODE"。请注意,Unicode和GBK、BIG5等ANSI编码仍然没有一种直接的算法进行转换,Unicode在制定时可以看成是废了所有的地区性编码,重新制定的编码,也不是从ASCII继承而来(但是前128字符仍保留为ASCII字符)。严格意义上说Unicode只是一套标准,为全世界文字给予一个唯一的编码,但是并没有规定在计算机中如果存储。所以根据Unicode标准来制定具体的实施方案就是UTF-8,UTF16以及UTF32它们规定了如何在计算机中存储、表示。

        先说UTF-16,对于Unicode标准中的文字,使用2个字节(16位)或4个字节来存储其编号。为什么是2个或4个字节表示呢?因为如果要包含全世界所有的符号文字,即使使用2个字节都无法包含,想想GBK编码,占满了2个字节仅仅包含我们大中华文字部分文字。但是针对各国的常用文字在2个字节内都能包含,所以通常使用2个字节的UTF16就足够了。所以在使用UTF16编码的文章或文档里,统计字符个数无需像ANSI那样麻烦,而且同一篇文章在各国的Windows等操作系统中使用UTF8打开不会造成乱码问题,十分方便。其实通常所说的Unicode指的就是UTF16

        UTF8,对于欧美的一些国家,常用的还是英文字母,如果使用UTF16,白白浪费一倍的存储空间(因为他们只需前128的字符就足够了)。针对此,UTF8产生了,它是一种变长编码方式,使用8位来实现Unicode中的所有字符,具体如何实现呢?

程序将一个字节一个字节的来读取,然后再根据每个字节中开头的标志来识别是该把一个还是两个或三个字节做为一个字符来处理.

(xx表示任意bit)

0xxxxxxx,以0开头表示把一个字节做为一个单元.就跟ASCII完全一样.

110xxxxx 10xxxxxx.如果是这样的格式,则把两个字节当一个单元

1110xxxx 10xxxxxx 10xxxxxx 如果是这种格式则是三个字节当一个单元.

也就是说UTF8编码的字符可能是1字节,可能是2字节也可能是3字节,数一下3字节中x的个数,16个,其最大的字符个数2的16次方,和UTF16相同。

         我们可以看出UTF-8需要判断每个字节中的开头标志信息,所以如果一当某个字节在传送过程中出错了,就会导致后面的字节也会解析出错.而UTF-16不会判断开头标志,即使错也只会错一个字符,所以容错能力强.

         但是由于UTF8对于一篇文章,占用的空间可能比UTF16小,而在在网络传输中由于是一个一个字节传输的,无需判断大端小端问题,所以UTF8在网络传输中十分普及。

UTF32,4个字节表示一个文字,普及率较UTF8和UTF16较小。(大端小端问题请查看我的博客里【大端小端模式详解】)

附带:BOM标记

一篇文章存储在内存中,使用记事本等工具打开时,记事本是怎么知道这篇文章使用什么编码方式呢?就是靠的位于文章最开头的BOM标记

前面说了要知道具体是哪种编码方式,需要判断文本开头的标志,下面是所有编码对应的开头标志(大端小端一般常见于网络传输中)

EF BB BF UTF-8

FE FF UTF-16/UCS-2,little endian

FF FE UTF-16/UCS-2,big endian

FF FE 00 00 UTF-32/UCS-4,little endian.

00 00 FE FF UTF-32/UCS-4,big-endian.

总结UTF-X(转自StackFlow):

·        UTF8: Variable-width encoding(变长编码), backwards compatible with ASCII. ASCIIcharacters (U+0000 to U+007F) take 1 byte, code points U+0080 to U+07FF take 2bytes, code points U+0800 to U+FFFF take 3 bytes, code points U+10000 toU+10FFFF take 4 bytes. Good for English text, not so good for Asian text.

·        UTF16: Variable-width encoding(变长编码). Code points U+0000 to U+FFFF take 2bytes, code points U+10000 to U+10FFFF take 4 bytes. Bad for English text, goodfor Asian text.

·        UTF32: Fixed-width encoding(定长编码). All code points take 4 bytes. Anenormous memory hog, but fast to operate on. Rarely used.

四、编码问题在编程语言中

        在C\C++中由于其诞生之时并没考虑语言编码问题,所以默认都使用DBCS方式编码,可以手动设置为Unicode,它们可以定义Unicode类型的字符串,但是类型需要使用wchar,本质只是unsigned short类型。

        而诞生比较晚的语言,如C#等语言,都是原生支持Unicode方式,具体使用UTF16形式编码(string类型只能为UTF16),一个char类型就占用2字节。
---------------------  
作者:张Da夫  
来源:CSDN  
原文:https://blog.csdn.net/zrf2112/article/details/50718641  
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/phoenixcsl/article/details/83418331