计算机字符编码详尽讲解

from http://www.guokr.com/blog/763017/

http://blog.csdn.net/stilling2006/article/details/4129700

下载一个文档,一打开发现是乱码,不抓狂才怪…… 你们都知道,这都是字符编码闯的祸。ASCII、ANSI、GB18030、Unicode、UTF-8、UTF-8 with BOM、UTF without BOM、UTF-16、UTF-16LE、UTF-16BE…… 一大坨的谁分得清?听说UTF-8就是Unicode,但怎么Windows记事本里的保存选项有UTF-8和Unicode两个选项呀?!究竟各种软件是怎样判断一个文件是什么编码呢?为什么有时候又判断错误呢?让我一一道来。

世界上本没有字符编码。自从有了计算机,我们有了用0和1记录文字的需求,于是字符就有了编码。

== ASCII ==

ASCII编码表示的“Hello GuoKr”(十进制):72 101 108 111 32 71 117 111 75 114

ASCII是最基本的编码,它定义了0~127对应的字符,包括最基本的英文字母、标点符号。它无法表示中文。ASCII编码的文本,每一个字节都是0~127,如果某个字节大于127,那它一定不是ASCII编码。

== GB* / ANSI ==

为了用计算机记录并显示中文,中国人发明了GB系列编码。GB系列编码定义了中文汉字、标点的编码。按照GB系列编码,在一段文本中,如果一个字节是0~127,那么这个字节的含义同ASCII编码,否则,这个字节和下一个字节共同组成汉字(或是GB编码定义的其他字符)。因此,GB系列编码向下兼容ASCII,也就是说,如果一段用GB编码文本里的所有字符都在ASCII中有定义,那么这段编码和ASCII编码完全一样。GB编码早期收录的汉字不足一万个,基本满足日常使用需求,但不包含一些生僻的字,后来在一个个新版本中加进去。最早的GB编码是GB2312,后来有GBK,最新的是GB18030,加入了一些国内少数民族的文字,一些生僻字被编到4个字节,每扩展一次都完全保留之前版本的编码,所以每个新版本都向下兼容。

同样,日文、韩文、世界各国文字都有了它们各自的编码(如果ASCII不能满足使用要求的话)。这些编码都和GB编码相似,兼容ASCII并用两个字节表示一个字。所有这些各国文字编码,微软统称为ANSI 。所以即使知道是ANSI,我们还需要知道这是哪国文字才能解码,因为这些编码都互相冲突。另外,你无法用一段ANSI 编码表示既有汉字、又有韩字的文本。

等等,上面我误导大家了……其实是微软误导大家了,严格来说ANSI 不是字符编码,而是美国一个非营利组织,他们做了很多标准制定工作,包括C语言规范ANSI C,还有各国文字编码对应的“代码页”(code page)。ANSI 规定简体中文GB编码的代码页是936,所以GB编码又叫做ANSI code page 936(按ANSI标准的代码页936),各国编码被统称为ANSI 由来于此——这是个离谱的历史错误,这就像我自己给国内的大学做了个排名,排名的依据是饭堂吃出虫子的概率,然后国内的大学就被统称为黄油猫。不过对于这些乱七八糟互相冲突的多国字符编码,有个统称还是不错的(我了个去还要谢谢微软),下面讨论姑且继续使用ANSI 。

==Unicode / UTF / UCS==

为了解决冲突的问题,促进世界和平,我们有了Unicode(联合码?)——一种将全世界所有语言所有字符都收录在一起、让它们和平共处的编码……哦,等等,Unicode虽是一种字符编码,但严格来说它和GB18030不能相提并论:它只定义了每一个字符对应一个整数(目前包含了十万多个字符,其中0~127和ASCII完全一样),但它没有定义这个整数如何变成字节。当你告诉我这段数据是Unicode编码,啊,不好意思,我还是不知道该怎么解码——因为变成字节流的格式不只一种,它们都叫做“Unicode转换格式”(Unicode Transformation Format,简称为UTF)。

所以这里面就有了一大堆UTF:UTF-8、UTF-8 with BOM、UTF-8 without BOM、UTF-16、UTF-16LE、UTF-16BE…… 还有很少见的UTF-32、,早期还会听说过UCS-2、UCS-4…… _(:з」∠)_

等等,为什么Windows记事本里有个保存选项是Unicode?这个稍后说。

先说最常见的UTF-8:它将一个字符编为1-4个字节,其中一个字节的字符和ASCII 完全一致,所以它也向下兼容ASCII。和ANSI类似,UTF-8第一个字节决定了之后多少个字节是一组好基友。多数汉字在UTF-8里为3个字节,有一些生僻的汉字会编到4字节。

我们迎来第一种不兼容ASCII的编码:UTF-16。UTF-16以每2个字节为一个单元,每个字符由1-2个单元组成,所以每个字符可能是2个字节或者4个字节,包括最常见的英文字母都会编成两个字节。大部分汉字也是2个字节,少部分生僻字为4个字节。UTF-16还有讲究,一个单元中的两个字节的顺序不是唯一的。学过计算机原理的同学知道,计算机中表示一个整数分两种格式:低位在前高位在后,或者反过来。例如用两个字节表示260这个整数,可能是:

低位在前:04 01 (260=4+256*1)

高位在前:01 04 (260=256*1+4)

低位在前的UTF-16叫UTF-16LE,高位在前的叫UTF-16BE。目前绝大部分的计算机系统都使用低位在前的整数格式,所以如果没有声明,UTF-16默认是LE。

早期Unicode收编的字还不多时,两个字节足够表示所有字符,所以有一种固定为两个字节的UTF,叫UCS-2。UTF-16的两个字节部分和UCS-2完全一样,所以UTF-16向下兼容UCS-2。UCS-2同样分LE和BE。而Windows的记事本还有Windows其它地方所谓的Unicode,当代的Windows里其实是UTF-16LE,在Windows XP和更早的版本里是UCS-2LE。微软(又是微软)正是混淆Unicode概念的祸首,微软你这么讨厌你家人知道吗?

此外,UTF-32和UCS-4固定为4个字节一个字符,同样分LE和BE。

还没完,这么多字符编码,软件打开时如何知道是哪个编码?于是不知道谁蹲坑时想出了BOM:在一个文本文件或者一段字符编码前加上几个固定的字节用于识别,这些字节保证不对应任何一个字符,所以软件一读就能验明正身:

EF BB BF - 我是UTF-8

FF FE - 我是UTF-16LE

FE FF - 我是UTF-16BE

(没有BOM,直奔主题)-你猜?

不错,没BOM只能靠猜了。软件读入文件时可以所有编码都试一下,看哪个像。另外,BOM只针对Unicode系列编码,ANSI通通不会有BOM。很显然,没有BOM难免偶然猜错。网上就流传了一个神奇的段子:打开Windows记事本,打入“联通”两个字,保存,关闭,再打开,变成了个黑块。记事本用ANSI(GB18030)保存联通这两个字,刚好这两个字的GB18030编码看起来很像UTF-16,于是就当成UTF-16来打开……

BOM听起来很不错,但实际是个讨厌的设计,因为它和很多协议、规范不兼容,这是题外话。

于是,UTF-8 with BOM、UTF-16 without BOM 你们就懂了。等等,如果不提BOM,究竟有BOM还是没有BOM?—— 又是一个十分纠结的问题,Windows里的软件一般都默认有BOM,而其它系统都默认没有BOM——可能是因为Windows常要兼容ANSI的原因,特别依赖BOM来防止会错意。

==谁是正统==

这么多种编码,用来写文章就罢了,打开个文档看到乱码就退出、换个程序或者换个编码再打开;但写程序时可半点马虎不得,各种程序开发环境对编码支持都不一样,如果编码没搞好,你写好的程序可能在别人计算机上就运行不起来了。如果我开发跨平台的代码,而且要有中文(注释),哪用什么编码好?以下是我所知道各开发环境/编译器支持常见编码情况(所有=ANSI、UTF-8 BOM and no BOM、UTF-16LE BOM and no BOM):

  • Visual Studio:所有,保存默认ANSI 。
  • VC编译器:所有,除了UTF-8 without BOM(直接当成是ANSI )
  • Windows记事本:所有,保存默认ANSI,无法保存无BOM。
  • XCode:只支持 UTF-8 without BOM。
  • GCC:所有
  • vim:所有,保存默认为系统默认编码,一般是UTF-8 without BOM。
  • Eclipse:所有,保存默认不明,Mac下居然是ANSI (我们中出了个叛徒)。

ANSI是无法跨境的,用GB写的文档拿去韩国就果断乱码了。光是简体中文系统,ANSI 也是经常被认错的,Eclipse里经常(不总是)出现打开ANSI 文件是乱码的情况,这是因为ANSI 没有很明显的特征。XCode和Mac的文本编辑器打开ANSI 直接是乱码,因为明确不支持。ANSI 容错性普遍比较差,一个字节错了可能导致后面的字通通挂掉。为了防止Eclipse等发神经,也为免跨国带来麻烦,更为了你自己的数据安全,请远离ANSI。

UTF-16不兼容ASCII,不兼容C语言的字符串处理库函数(因为字节流里有\0),除了Windows爱用,其它系统都痛恨它。BOM和很多协议规范冲突,很多软件都抵制,也是只有Windows常用,而且将其列为正统(作反)。

综上,跨平台开发请使用UTF-8 without BOM,那是最通用的编码,是很多软件系统的默认编码,你在看的网页也用它。它特征明显,除了VC编译器和微软的各种软件外暂时没发现哪个软件会有认错的情况。它还有经过精心设计的容错机制,错一个字节最多只会错一个字符。请手动设置你的开发环境,将默认保存的编码设为UTF-8 without BOM,并将其它编码的文件转换过来,乱码就拜拜啦;记事本等不支持的编辑器,不要让他们摸你的文件。至于VC编译器硬要闹别扭就由它去吧 _(:з」∠)_

(经过测试,VS2010能正常打开UTF-8 without BOM的代码,但可能编译不通过,并报奇怪的编译错误)

为什么程序猿那么喜欢黑微软啊?因为微软那群闷骚的设计师总是和大家不太一样……

写在最后:

在这个机器能听懂人语的年代,我们还要操心字符编码这么低级的事,真是不可思议…… 解决方案这么简单:几家大公司坐一圈,说定一种编码,以后通通用一种编码。而且这种编码已经浮出水面、支持成熟:UTF-8。我很赞赏苹果,他们果断和ANSI还有一大堆不统一的编码一刀两段,所有软件只支持UTF-8,这才是真正对用户负责 —— 而微软到今天还死抱着ANSI不放,在这件小事上就看出他就是如此不舍得过去一点的成就,如此不舍得革自己的命。

时间: 2024-10-22 00:12:42

计算机字符编码详尽讲解的相关文章

遇到乱码不怕不怕啦——计算机字符编码详尽讲解

下载一个文档,一打开发现是乱码,不抓狂才怪…… 你们都知道,这都是字符编码闯的祸.ASCII.ANSI.GB18030.Unicode.UTF-8.UTF-8 with BOM.UTF without BOM.UTF-16.UTF-16LE.UTF-16BE…… 一大坨的谁分得清?听说UTF-8就是Unicode,但怎么Windows记事本里的保存选项有UTF-8和Unicode两个选项呀?!究竟各种软件是怎样判断一个文件是什么编码呢?为什么有时候又判断错误呢?让我一一道来. 世界上本没有字符编

计算机字符编码问题

参考链接: 字符编码笔记:ASCII,Unicode和UTF-8 中文编码杂谈 程序员趣味读物:谈谈Unicode编码 http://www.unicode.org/ GB2312简体中文编码表 中日韩Unicode编码表

python学习第十八天计算机字符编码

人类语言和计算机语言二进制怎么沟通,最开始字符编码为ascii码对照表 包括数据和字母,没有汉字,中国自己搞了一套自己的编码 gb2312编码后来发展GBK编码,日本,韩国都,甚至台湾也搞自己的编码,最后国际统一一个编码为unicode 编码 但是unicode编码统一占两个字符,英文占一个字符,中文占两个字符,泰文占3个字符,后来发展 演变 统一 UTF格式 utf-8,这种可长可短的,比较适合所有国家的编码方式. 1,二进制 0,1 二进制 0,1,2,3,4,5,6,7 八进制 0.1.2

转 计算机字符编码中GBK GB2312 GB18030有什么区别

GBK和GB2312 都是16位的, GBK支持简体中文和繁体中文,而GB2312只支持简体中文,GBK里面包含了GB2312,用GBK比较多 GB18030是32位的,它支持简体中文.繁体中文 藏文.蒙文.维吾尔文等主要的少数民族文字, 包含GBK和GB2312 也就是说从GB2312(1980年).GBK(1995年)到GB18030(2000年),这些编码方法是向下兼容的

计算机在字符编码

计算机字符编码 1.编码发展历史简介   http://www.cnblogs.com/jessonluo/p/4800331.html 使用的字符编码都兼容 ASCII 码 下面主要讲解下 Unicode 编码 ,也就是 万国码 2.Unicode  只是一个编码方案,不是具体的实现 Unicode 编码 只是一种 方案,UTF-8 .UTF-16.UTF-32 才是 Unicode 编码的实现. 原文地址:https://www.cnblogs.com/wfblog/p/10642793.h

python --- 字符编码学习小结

上半年的KPI,是用python做一个测试桩系统,现在系统框架基本也差不多定下来了.里面有用到新学的工厂设计模式以及以及常用的大牛写框架的业务逻辑和python小技巧.发现之前自己写的代码还是面向过程思想的多,基本没有面向对象的思想,近半年看的代码给了很大的触动,我需要升级我的技能了,于是也花了挺多时间在这个KPI学习上,现在先总结下在做这个系统时我所面临到的python的字符编码问题. 字符编码问题,如果处理有问题,可能直接就报错了:如果处理不得当,中文就会显示乱码.这是最初接触字符编码遇到问

计算机中的字符编码详解

前记: 现在有一个想法: 实现自己的一个开源分词系统,这个计划说大不大,说小也不是很easy.目前的计划是先通读 ansj与HanLP的源码. 读源码是一种进步很快的方式,就是刚开始会感觉很痛苦,刚读就发现,所知甚少,所以 吾生也有涯而学也无涯,慢慢来吧 我想会更新一系列关于这两个项目的博文,目前看得比较少,没什么好写的,算是起始状态,算个Day 1 吧. 过几天可能会写一篇Tire树的,这种树常用来作为分词中查找词典的基本数据结构,在java源代码中是以汉字的int值作为下标的,于是想看一下这

走入计算机的 第十七天(python的字符编码和函数)

一  字符编码的只是储配 1. 文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就打开了启动了一个进程,是在内存中的,所以在编辑器编写的内容也都是存放与内存中的,断电后数据丢失 因而需要保存到硬盘上,点击保存按钮,就从内存中把数据刷到了硬盘上. 在这一点上,我们编写一个py文件(没有执行),跟编写其他文件没有任何区别,都只是在编写一堆字符而已. 2. python解释器执行py文件的原理 ,例如python test.py 第一阶段:python解释器启动,此

计算机中的字符编码

字符编码 什么是计算机编码 计算机只能处理二进制的数据,其它的数据都要进行转换,但转换必须要有一套字符编码(是字符与二进制的一个对应关系).常用的字符:a-z.0-9.其它的符号等,计算机也不能直接处理. (字符编码类似于翻译的字典) 常用的计算机编码(字符集.字符编码) ASCII编码:American Standard Code for Information Interchange美国信息交换标准代码 用1个字节(7位或8位二进制)来表示一个字符.比如:字母a,用二进制表示01100001