UTF-8编码
UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8的编码规则很简单,只有二条:
1.对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2.对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
下表总结了编码规则,字母x表示可用编码的位。0000 0000-0000 007F0xxxxxxx
0000 0080-0000 07FF110xxxxx 10xxxxxx
0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
跟据上表,解读UTF-8编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
下面,还是以汉字”严”为例,演示如何实现UTF-8编码。
已知”严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此”严”的UTF-8编码需要三个字节,即格式是”1110xxxx 10xxxxxx 10xxxxxx”。然后,从”严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,”严”的UTF-8编码是”11100100 10111000 10100101”,转换成十六进制就是E4B8A5。
UTF-16编码
UTF-16是Unicode的其中一个使用方式。 UTF是 Unicode TransferFormat,即把Unicode转做某种格式的意思。UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却无法兼容于ASCII编码。UTF-16的大端和小端储存形式都在用。为了弄清楚UTF-16文件的大小端,在UTF-16文件的开首,都会放置一个U+FEFF字符作为Byte Order Mark(UTF-16LE以FF FE代表,UTF-16BE以FE FF代表),以显示这个文字档案是以UTF-16编码,其中U+FEFF字符在UNICODE中代表的意义是ZERO WIDTH NO-BREAK SPACE,顾名思义,它是个没有宽度也没有断字的空白。
实例讲解
例1
输出的结果是什么呢?
FE FF 0 49 0 27 0 6D 0 20 67 4E 53 5A 73 89
16
49 27 6D 20 E6 9D 8E E5 8D 9A E7 8E 89
13
1.UTF-16的编码为什么是16?
对于大部分字符来讲,UTF-16都使用两个字节来存储。但是UTF-16是支持大小端的,所以需要在字符的开头使用两个字节的额外空间指定好它的字节序,FE FF 表示使用大端存储。
7 x 2 + 2 = 16
2.UTF-8的编码为什么是13?
UTF-8是完全兼容ASCII编码的,所以英文是占一个字节,中文大部分占3个字节,不常用的占4个字节
4 + 3 x 3 = 13
例2
String s1 = “李”;
String s2 = ““
System.out.println(s1.length());
System.out.println(s2.length());
输出的结果是什么呢?
1
2
看到这个结果是不是崩溃了,到底怎么回事?
1.首先要明白.length指的是什么,String内部是以char数组的形式存储的,.length是指char数组的长度,char是以UTF-16编码的,李是常用字,UTF-16编码后占两个字节,一个char就能够存储,所以是长度是1,而UTF-16编码后占四个字节,两个char来存储,所以长度是2