常用字符集及字符编码和Charset类

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。

  • 字符(Character) :是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
  • 字符集(Character Set/Charset):是一个系统支持的所有抽象字符的集合。由多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,字符和二进制数字的对应规则不同。        常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GBK字符集、Unicode字符集等。        
  • 字符编码(Character Encoding):是一套法则,把字符集中的字符编码为特定的二进制数,以便在计算机中存储。每个字符集中的字符都对应一个唯一的二进制编码。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

字符集和字符编码一般都是成对出现的,如ASCII、IOS-8859-1、GB2312、GBK,都是即表示了字符集又表示了对应的字符编码。Unicode比较特殊,有多种字符编码(UTF-8,UTF-16等)。 

一、常用字符集和字符编码

1、ASCII字符集&编码

ASCII(American Standard Code for Information Interchange, 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本EASCII则可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。

字符集范围

ASCII一共定义了128个字符,包括33个控制字符和95个可显示字符。大部分的控制字符已经被废弃。

编码格式

ASCII码为单字节,使用7 位二进制数(剩下的1位二进制为0),由于计算机1个字节是8位二进制数,所以最高位为0,即00000000-01111111或0x00-0x7F。

    

   Unicode,GBXXX,UTF-8等字符编码都兼容ASCII编码。

2、GB2312字符集&编码

GB 2312 或 GB 2312–80 是中华人民共和国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,又称GB0,由中国国家标准总局发布,1981年5月1日实施。GB 2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。

字符集范围

GB 2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个字符。GB 2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。但对于人名、古汉语等方面出现的罕用字和繁体字,GB 2312不能处理,因此后来GBK及GB 18030汉字字符集相继出现以解决这些问题。

分区

GB 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。

  • 01–09区为特殊符号。
  • 16–55区为一级汉字,按拼音排序。
  • 56–87区为二级汉字,按部首/笔画排序。

举例来说,“啊”字是GB 2312之中的第一个汉字,它的区位码就是1601。10–15区及88–94区则未有编码。

编码格式

在使用GB 2312的程序通常采用EUC储存方法,以便兼容于ASCII。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。
“高位字节”使用了0xA1–0xF7(把01–87区的区号加上0xA0),“低位字节”使用了0xA1–0xFE(把01–94加上0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0–0xF7,“低位字节”的范围是0xA1–0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA–D7FE。

3、GBK字符集&编码

汉字内码扩展规范,称GBK,全名为《汉字内码扩展规范(GBK)》1.0版,由中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订,国家技术监督局标准化司和电子工业部科技与质量监督司1995年12月15日联合以《技术标函[1995]229号》文件的形式公布。GBK的K为汉语拼音Kuo Zhan(扩展)中“扩”字的声母。英文全称Chinese Internal Code Extension Specification。

字符集

GB 2312-80只收录6763个汉字,有不少汉字,如部分在GB 2312-80推出以后才简化的汉字(如“啰”),部分人名用字(如中国前总理朱镕的“镕”字),台湾及香港使用的繁体字,日语及朝鲜语汉字等,并未有收录在内。GBK对GB 2312-80进行扩展, 总计拥有 23940 个码位,共收入21886个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号883 个。

编码格式

GBK 亦采用双字节表示,总体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间,剔除 xx7F一条线。

    

GBK向下完全兼容GB2312-80编码。支持GB2312-80编码不支持的部分中文姓,中文繁体,日文假名,还包括希腊字母以及俄语字母等字母。不过这种编码不支持韩国字,也是其在实际使用中与unicode编码相比欠缺的部分。

4、GB 18030字符集&编码

GB 18030,全称:国家标准GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集,是GB 18030-2000《信息技术 信息交换用汉字编码字符集 基本集的扩充》的修订版。与GB 2312-1980完全兼容,与GBK基本兼容;支持GB 13000(93版等同于Unicode 1.1;2010版等同于Unicode 4.0)及Unicode的全部统一汉字,共收录汉字70,244个。

本规格的初版是由中华人民共和国信息产业部电子工业标准化研究所起草,由国家质量技术监督局于2000年3月17日发布。现行版本为国家质量监督检验总局和中国国家标准化管理委员会于2005年11月8日发布,2006年5月1日实施。

此标准内的单字节编码部分、双字节编码部分,和四字节编码部分收录的中日韩统一表意文字扩展A区汉字,为强制性标准。其他部分则属于规模性标准。在中华人民共和国境内所有软件产品,都需要支持这个同时包含单字节、双字节和四字节编码的规格。

GB 18030主要有以下特点:

  • 和UTF-8一样都采用多字节编码,每个字可以由1个、2个或4个字节组成。
  • 编码空间庞大,最多可定义161万个字元。
  • 支持中国国内少数民族的文字,不需要动用造字区。
  • 汉字收录范围包含繁体汉字以及日韩汉字。

编码方式

  • 单字节,其值从0x00到0x7F。
  • 双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)。
  • 四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节从0x81到0xFE,第四个字节从0x30到0x39。

5、Unicode字符集&编码

Unicode(中文:万国码国际码统一码单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。Unicode伴随着通用字符集的标准而发展,同时也以书本的形式对外发表。Unicode至今仍在不断增修,每个新版本都加入更多新的字符。目前最新的版本为2016年6月21日公布的9.0.0,已经收入超过十万个字符(第十万个字符在2005年获采纳)。Unicode涵盖的数据除了视觉上的字形、编码方法、标准的字符编码外,还包含了字符特性,如大小写字母。

Unicode发展由非营利机构统一码联盟负责,该机构致力于让Unicode方案替换既有的字符编码方案。因为既有的方案往往空间非常有限,亦不适用于多语环境。

Unicode备受认可,并广泛地应用于电脑软件的国际化与本地化过程。有很多新科技,如可扩展置标语言、Java编程语言以及现代的操作系统,都采用Unicode编码。

编码方式

统一码的编码方式与ISO 10646的通用字符集概念相对应。目前实际应用的统一码版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示2的16次方(即65536)个字符。基本满足各种语言的使用。实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。

Unicode原编码占用两个字节,在使用ASCII字符时,高位字节的8位始终为0,这会造成空间的浪费。为了避免这种浪费,Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

6、UTF-8 编码

UTF-88-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。

UTF-8使用一至六个字节为每个字符编码(尽管如此,2003年11月UTF-8被RFC 3629重新规范,只能使用原来Unicode定义的区域,U+0000到U+10FFFF,也就是说最多四个字节):

  1. 128个US-ASCII字符只需一个字节编码(Unicode范围由U+0000至U+007F)。
  2. 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码(Unicode范围由U+0080至U+07FF)。
  3. 其他基本多文种平面(BMP)中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码(Unicode范围由U+0800至U+FFFF)。
  4. 其他极少使用的Unicode 辅助平面的字符使用四至六字节编码(Unicode范围由U+10000至U+1FFFFF使用四字节,Unicode范围由U+200000至U+3FFFFFF使用五字节,Unicode范围由U+4000000至U+7FFFFFFF使用六字节)。

对上述提及的第四种字符而言,UTF-8使用四至六个字节来编码似乎太耗费资源了。但UTF-8对所有常用的字符都可以用三个字节表示,而且它的另一种选择,UTF-16编码,对前述的第四种字符同样需要四个字节来编码,所以要决定UTF-8或UTF-16哪种编码比较有效率,还要视所使用的字符的分布范围而定。

编码方式

  • 单字节字符的最高有效比特永远为0。
  • 多字节序列中的首个字符组的几个最高有效比特决定了序列的长度。最高有效位为110的是2字节序列,而1110的是三字节序列,如此类推。
  • 多字节序列中其余的字节中的首两个最高有效比特为10

二、Charset类

编码(encode):把明文的字符序列转化成二进制的字节序列。

解码(decode):把二进制的字节序列转换成明文的字符序列。

Java默认使用使用Unicode字符集,但是有的操作系统不支持,所以当从操作系统读取到Java程序时,就可能出现乱码的情况。

JDK1.4提供了Charset来处理字节序列和字符序列(字符串)之间的转换,Charset类是不可变类。

 Set<String>aliases()
          返回包含此 charset 各个别名的集合。
static SortedMap<String,Charset>availableCharsets()
          构造从规范 charset 名称到 charset 对象的有序映射。
static CharsetdefaultCharset()
          返回此 Java 虚拟机的默认 charset。
static CharsetforName(String charsetName)
          返回指定 charset 的 charset 对象。
static booleanisSupported(String charsetName)
          通知是否支持指定的 charset。
 Stringname()
          返回此 charset 的规范名称。
abstract  CharsetDecodernewDecoder()
          为此 charset 构造新的解码器。
abstract  CharsetEncodernewEncoder()
          为此 charset 构造新的编码器。

该类包含了用于创建解码器和编码器的方法,还提供了获取Charset所支持字符集的方法等。

Charset类提供了一个availiableCharset()静态方法来获取当前JDK支持的所有字符集。

    public static void main(String[] args) {
        SortedMap<String, Charset> map = Charset.availableCharsets();
        map.forEach((key, value) ->{
            System.out.println("key=" + key + ", value=" + value);
        });
    }

    

一旦知道字符集的别名后,就可以使用Charset的forName()方法来创建对应的Charset对象,

然后调用它的newDecode()/newEncode()这两个方法返回CharsetDecoder/CharsetEncoder对象,创建对应的编码器和解码器对象。这两个对象代表Chars的解码器和编码器。

调用CharsetDecoder的decode方法就可以将字符序列字节序列转换成字符序列(ByteBuffer)->(CharBuffer),同理调用encode就可以将字符序列转换成字节序列。

在String类里面提供了一个getBytes(String charset)方法。该方法返回byte[],该方法同样可以将制定字符集转换成字节序列。

注意:通常情况下大小写都能识别,最好使用大写,如UTF-8、GBK。

1、使用CharsetEncoder编码器将CharBuffer(字符串)转换为ByteBuffer

2、使用CharsetDecoder解码器将ByteBuffer转换为字符序列CharBuffer(字符串)

    public static void main(String[] args) throws Exception {
        // 创建GBK对应的Charset,并创建编码器
        Charset charset = Charset.forName("GBK");
        CharsetEncoder charsetEncoder = charset.newEncoder();

        // 创建CharBuffer对象,放点数据
        CharBuffer charBuffer = CharBuffer.allocate(1024);
        charBuffer.put("字符序列与字节序列转换");
        charBuffer.flip();

        // 通过编码器,将CharBuffer转换成byteBuffer
        ByteBuffer byteBuffer = charsetEncoder.encode(charBuffer);
        // byteBuffer读数据打印
        for (int i = 0; i < byteBuffer.limit(); i++) {
            System.out.print(byteBuffer.get(i) + " ");
        }

        // 通创建解码器,将ByteBuffer转换成CharBuffer
        CharsetDecoder charsetDecoder = charset.newDecoder();
        CharBuffer charBuffer1 = charsetDecoder.decode(byteBuffer);
        System.out.println(charBuffer.position());
        while (charBuffer1.remaining() > 0) {
            System.out.print(charBuffer1.get() + " ");
        }
    }

 

参考文章:

常见字符集及编码

GBK,BIG5,UCS等字符集编码范围的具体说明

GB2312, BIG5, UTF8, Unicode之间的互换

 

—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值