字符编码的理解

今天遇到了个字符编码的问题,在这总结一下自己的简单理解:

1.首先区分字符集和字符编码这两个概念才比较好理解

字符集:就是一个文字,标点符号等的集合

字符编码:就是把字符集中的字符和其他指定集合的一个元素相互对应。例如:unicode编码把unicode字符集和0x00000000~0xFFFFFFFF对应,ascii编码把ascii字符集和0~127.

2.ascii,iso-8859-1,GB,unicode等字符集

计算机出现不久后,为了计算机的发展,美国发布了ascii标准,这个字符集只有128个,对应这7个二进制。由于美国计算机一直领先,因而这个标准影响广泛。但是对于欧洲其他一些国家而言例如:法国,德国,ascii字符集并没有包含法语,德语所有的字符。因而在ascii字符集基础上扩展了iso-8859-1,iso-8859-1字符集有256个字符,用一个字节表示完,iso-8859-1前128个字符和ascii相同

对于中国而言,ascii只是英文,并不适合中国平时处理汉字的需要,因而中国在ascii字符集基础上扩展增加了汉子形成gb2312字符集,他用两个字节表示汉字,GB 2312的出现,基本满足了汉字的计算机处理需要,但对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致了后来GBK及GB 18030的出现。

unicode:各国国家都有自己的字符集和字符编码方案,为了统一世界所有的字符出现了unicode,使用0x00000000~0xFFFFFFFF来表示,共4个字节。但是实际目前只是用了0x00000000~0x0010FFFF共100多万个。这100多万分布在 17 个 代码平面(code plane,每个平面有2的16次方个)里面。

U+0000 ~ U+FFFF       基本多语言平面BMP(Basic Multilingual Plane),

U+10000 ~ U+10FFFF  辅助平面SMP (Supplementary Plane), 这些处于辅助平面的字符我们称作 增补字符(supplementary characters)。

3   unicode编码方案

Unicode只是一个符号集,unicode编码它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。因此要有编码方案把unicode字符映射到可以适合存储的二进制。常用的方案有:utf-32,utf-16,utf-8

utf-32:用4个字节表示一个unicode的字符,例如:a用0x00000061。但这种效率很低,因为unicode本身只用了100多万,而4字节(2的32次方)有40多亿。

utf-16: 用2个字节或4个字节表示一个unicode,例如:a用0x0061。对于基本多语言平面BMP(Basic Multilingual Plane)用两个字节表示,对于辅助平面SMP (Supplementary Plane)用四个字节表示,即一个辅助平面的字符,被拆成两个基本平面的字符表示,其原理:在基本平面内,从U+D800到U+DFFF是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。

U+D800到U+DBFF(空间大小210),称为高位(H),

U+DC00到U+DFFF(空间大小210),称为低位(L)。

所以,当我们遇到两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定,紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。

Unicode码点转成UTF-16的时候,首先区分这是基本平面字符,还是辅助平面字符。如果是前者,直接将码点转为对应的十六进制形式,长度为两字节。例如:‘张’   这个字符 unicode编码位 U+5F 20,其utf16为0x5F 20。 如果是辅助平面字符,使用转码公式:

H = Math.floor((c-0x10000) / 0x400)+0xD800
L = (c - 0x10000) % 0x400 + 0xDC00

utf-8:是一种更加节省空间的编码方案,它是一种变长的编码方法,字符长度从1个字节到4个字节不等。越是常用的字符,字节越短,最前面的128个字符,只使用1个字节表示,与ASCII码完全相同。

编号范围                                 字节
0x0000 - 0x007F        1
0x0080 - 0x07FF        2
0x0800 - 0xFFFF        3
0x010000 - 0x10FFFF      4

4.java中char和字符串的字符编码问题

 Java采用UTF-16编码作为内码,也就是说在JVM内部文本字符的编码为UTF-16,java常用的文本类型就是字符(char)和字符串(String),但是在 Java 中 char 数据类型是定长的(换种说法就是char类型的编码是一种带有限制的UTF-16编码,因为UTF-16的一个字符的长度可能是2字节也可能是4字节),其长度永远只有 16 位,char 数据类型永远只能表示代码点在 U+0000 ~ U+FFFF 之间的字符,也就是在 BMP 内的字符,如果超过了这个范围,即使用了增补字符,那么 char 数据类型将无法支持。String也是UTF-16,但是string中的字符没有永远只有 16 位这个限制,它能够支持增补字符,即它的一个字符的长度可能是16位也可能是32位。

其中要注意字符串长度问题:

对于string,其底层是char[]  即char数组,其length()方法是数组长度,但是如果是想知道字符串中完整字符的长度要用codePointCount方法。

解释:一个完整的“字符”是一个code point;一个code point可以对应1到2个code unit;一个code unit是16位。只有只需1个code unit的code point才可以完整的存在char里。但String作为char的序列,可以包含由两个code unit组成的“surrogate pair”来表示需要2个code unit表示的UTF-16 code point。为此Java的标准库新加了一套用于访问code point的API,而这套API就表现出了UTF-16的变长特性。

在这总结一下在java中从源码到运行要碰到的字符编码问题,字符通常会出现在三个地方:

  1. Java源码文件,*.java,可以是任意字符编码,如GBK,UTF-8
  2. Class文件,*.class,采用的是一种改进的UTF-8编码
  3.  JVM,内存中使用UTF-16编码

首先从源码开始,源码java文件可以GBK,UTF-8等编写。写好源码后要编译,这时Java编译器需要知道源码文件的编码才能正确编译,默认情况下编译器它会取操作系统的编码,可以使用参数-encoding指定源码文件的字符编码。编译器正确读取源码后会编译成UTF-8编码的Class文件。运行时,JVM加载Class文件,把其中的字符或字符串转成UTF-16编码序列

 

    

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值