详说字符编码

转载 2015年11月19日 13:13:39

字符编码

字符编码概述

 

1 字符编码是什么?

我们知道,计算机数据只能是二进制的,数值类型的数据转换成二进制很简单,我们已经了解了,但字符类型如何转换成二进制呢?这就需要使用字符编码!

在编码表中,每个字符都有对应的编码,编码是整数,最终在计算机中存储的是字符的编码,而不是字符本身(因为计算机数据都是二进制数值,所以字符本身是无法存储的)。

当我们存储字符’A’时,其实是通过编码表找到’A’字符对应的编码,然后把编码存储在计算机中。即存储的是65。

当我们读取字符时,其实读取的也是字符的编码,然后使用编码再去编码表中查找对应的字符显示。

       
 
   
 

2 常见的字符编码

l  ASCII

在所有字符集中,最知名的可能要数被称为ASCII的7位字符集了。它是美国标准信息交换代码(American Standard Code for Information Interchange)的缩写, 为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成。

 

l  ISO-8859-1

由于ASCII是针对英语设计的,当处理带有音调标号(形如汉语的拼音)的欧洲文字时就会出现问题。因此,创建出了一些包括255个字符的由ASCII扩展的字符集。有一种8位字符集是ISO 8859-1Latin 1,也简称为ISO Latin-1。它把位于128-255之间的字符用于拉丁字母表中特殊语言字符的编码,也因此而得名。

 

l  GB2312

GB2312是一个简体中文字符集的中国国家标准,全称为《信息交换用汉字编码字符集•基本集》,又称为GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。

GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时,GB 2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。

对于人名、古汉语等方面出现的罕用字,GB2312不能完全包括,这导致了后来GBK及GB18030汉字字符集的出现。

GB2312兼容ASCII码,这部分还是每个字符占1个字节。每个汉字字符占2个字节。GB2312是中国自己的字符集,而其他国家也都有自己的字符集!!!

 

l  Unicode

Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的编码,以满足跨语言、跨平台进行文本转换、处理的要求。它通过增加一个高字节(2个字节)对ISO Latin-1字符集进行扩展,当这些高字节位为0时,低字节就是ISO Latin-1字符。UNICODE支持欧洲、非洲、中东、亚洲(包括统一标准的东亚象形汉字和韩国象形文字)。但是,UNICODE并没有提供对诸如Braille,Cherokee, Ethiopic, Khmer, Mongolian, Hmong, Tai Lu, Tai Mau文字的支持。同时它也不支持如Ahom, Akkadian, Aramaic, Babylonian Cuneiform, Balti, Brahmi,Etruscan, Hittite, Javanese, Numidian, Old Persian Cuneiform, Syrian之类的古老文字。Unicode支持ISO Latin-1(ISO-8859-1),而Latin-1包含了ASCII编码表。

 

l  UTF-8

事实证明,对可以用ASCII表示的字符使用UNICODE并不高效,因为UNICODE比ASCII占用大一倍的空间,而对ASCII来说高字节的0对他毫无用处。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF(UniversalTransformation Format)。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32。

UTF-8只是Unicode编码的一种转换方式,这时因为Unicode问题占用两个字节的空间,而且最为常用的ASCII编码部分只需要一个字节就可以了,所以才会出现通用转换格式(UTF)。

UTF-8对不同范围的字符使用不同长度的编码,ASCII编码部分与ASCII一样,都是1个字节。而汉字部分都是3个字节。

 

Unicode转换到UTF-8规则如下:

 

1.      如果Unicode编码的16位二进制数的前9位是0, 则UTF-8编码用一个字节来表示,这个字节的首位是0,剩下的7位与原二进制数据的后7位相同。例如:

 

     Unicode编码:\u0061 = 00000000 01100001

     UTF-8编码: 01100001 = 0x61

 

2.      如果Unicode编码的16位二进制数的头5位是0,则UTF-8编码用2个字节来表示,首字节用110开头,后面的5位与原二进制数据去掉前5个零后的最高5位相同;第二个字节以10开头,后面的6位与原二进制数据的低6位数据相同。例如:

 

Unicode编码: \u00A9 =00000000 10101001

UTF-8编码: 11000010 10101001 =0xC2  0xA9

 

3.      如果不符合上述两个规则,则用3个字节表示。第一个字节以1110开头,后四位为原二进制数据的高四位,第二个字节以10开头,后六位为原二进制数据的中间6位,第三个字节以10开头,后6位为原二进制数据的低6位。例如:

 

Unicode编码: \u4E2D =01001110 00101101

UTF-8编码: 11100100 1011100010101101 = 0xE4 0xB8 0xAD

 

                   把Unicode为                    0101-11010001-0100                        (5D14)

转换成UTF-8后为:      1110-0101 1011-0100 1001-0100   (E5B494)

 

编码相关功能

汉字“崔”的编码:

l  GBK:                 0xB4DE

l  Unicode:          0x5D14

l  UTF-8:              0xE5B494

 

1       获取字符串中所有字符的编码

String类的getBytes(StringcharName)方法可以用来获取当前字符串的据的字符的编码,返回值为字节数组。

l  byte[] getBytes():返回GBK编码的字节数组;

l  byte[] getBytes(String charsetName):返回指定编码的字节数组。该方法声明了UnsupportedEncodingException异常,该异常是IOException的子类,当Java不支持指定的编码时会抛出这个异常。

 

byte[] b1 = “崔”.getBytes();// [-76, -34]

byte[] b1 = “崔”.getBytes(“GBK”);// [-76, -34]

byte[] b2 = “崔”.getBytes(“UTF-8”);// [-27, -76, -108]

byte[] b3 = “崔”.getBytes(“Unicode”);// [-2, -1, 93, 20]-2-1是没有意义的。

 

  虽然上面使用的都是字符串“崔”,但获取的编码结果是不同的。这时因为Java使用相同的字符去查找不同的编码表得到的结果。

 

2       字符串类与字符编码

在Java中,字符都是使用Unicode编码(其实是UTF-16的一种方式),每个字符都占两个字节。而我们使用的OS都是使用GBK编码(当然,这需要你安装中文操作系统),也就是说文本文件中默认使用的都是GBK编码。

现在我们有一个字节数组,它表示的是GBK编码的汉字“崔”,例如:

 

byte[] buff = {-76, -34};

 

现在我们要把它转换成字符串,这需要使用String类的构造器:

 

       String s = new String(buff, "GBK");

 

这个构造器需要指定字节数组,以及这个字节数组使用的编码表。其实,如果你不指定编码表,String类的构造器也会使用默认的编码表来把字节数组转换成字符串的。默认的编码表就是系统默认编码表,对中文操作系统来说就是GBK。

  new String(buff, “GBK”)的意思是:拿着buff这个编码,去查找”GBK”编码表,找到我们想要的字符,构成一个字符串。

 

       byte[] buff = {-76, -34};

       String s = new String(buff);

    System.out.println(s);

 

上面代码打印的还是汉字“崔”。但如果你使用其他的编码表,例如使用UTF-8,那么一定会出现乱码。因为你的字节数组本身是对应GBK编码表的,但非要告诉String构造器去对照UTF-8编码表,那查出来的字符当前是错误的了!

乱码的出现,就是因为使用了错误的编码表造成的!!!

 

 

详说分页

    在使用数据库的过程中,不可避免的需要使用到分页的功能,可是JDBC的规范对此却没有很好的解决。对于这个需求很多朋友都有自己的解决方案,比如使用Vector等集合类先保存取出的数据再分页。但这种...
  • oicqren
  • oicqren
  • 2004年11月16日 20:03
  • 744

详说Subversion备份

版本控制最关键的一件事是保证数据的安全性,不能因为磁盘损坏,程序故障造成版本库无可挽回的错误,为此必须制定较完备的备份策略。在Subversion中,我们有三种备份方式:完全备份,增量备份和同步版本库...
  • csj50
  • csj50
  • 2008年06月18日 13:27
  • 599

web性能优化:详说浏览器缓存

TOC 背景浏览器的总流程图一步一步说缓存 朴素的静态服务器设置缓存超时时间html5 Application CacheLast-Modified/If-Modified-SinceEt...
  • dz45693
  • dz45693
  • 2016年06月13日 11:16
  • 896

[绍棠] 详说CMDeviceMotion

对于使用了M7或者M8处理器的设备,Core Motion框架支持了一些预置的motion动作,比如脚步数、爬楼还有移动类型(行走、骑行等等)。 Core Motion可以让开发者从各个内置传感...
  • happyshaotang2
  • happyshaotang2
  • 2016年08月19日 10:28
  • 481

详说CMDeviceMotion

深藏于每台iPhone光滑的屏幕之下,处于触摸屏与芯片之间,依偎在逻辑板之上的陀螺仪和加速器总是被众人所遗忘。 所以这些玩意拿来干嘛?当然是用来在旧式的点击和滑动之外开创新交互方式的啦,这里就要...
  • whgggg
  • whgggg
  • 2014年11月03日 13:24
  • 845

详说 Subversion备份

导读:   作者:Rock Sun, Subversion中文站。   如有转发请注明出处:http://www.subversion.org.cn/index.php?option=com_cont...
  • zhijie435
  • zhijie435
  • 2007年12月17日 13:56
  • 577

详说清除浮动

来自:http://kayosite.com/remove-floating-style-in-detail.html 浮动,从诞生那天起,它就是个特别的属性——既为网页布局...
  • Hookc
  • Hookc
  • 2013年12月24日 10:22
  • 695

详说处理器

处理器是什么,从字面上来理解就是处理事物的机器。是目前广泛使用的中央处理器的简称。下面就聊聊这个东西的各各方面。   现在的处理器从运行使用原理上可以分为两类,即RISC和CISC两种处理器,RIS...
  • u011511146
  • u011511146
  • 2013年07月25日 22:18
  • 356

static详说

。。。。。。 
  • fg100emil
  • fg100emil
  • 2006年11月29日 23:09
  • 519

详说WAP

20世纪90年代以来,有两种技术得到了广泛应用,他们直接影响了亿万人的生活,大大地改变了人类的生活方式,那就是Internet和移动电话。 Internet使得全球的人们能够方便地、廉价地去访问大量的...
  • kiss0kill
  • kiss0kill
  • 2006年10月30日 09:57
  • 694
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:详说字符编码
举报原因:
原因补充:

(最多只允许输入30个字)