Unicode UTF-8 UTF-16编码问题

时间:2023-01-11 12:00:26

Unicode UTF-8 UTF-16

二进制,十进制和十六进制

在Java中一个字节(byte)由八位组成
对于1000 0110
转化为有符号十进制: -122
转化为无符号十进制: 134
转化为十六进制: 86
tips:最高位为1,一般我会算低七位的值,转化为有符号-128,转化为无符号+128

在Java里,byte -> int,int为有符号十进制


Unicode

最新的Unicode采用四个字节表示全部字符,范围为0x0 - 0x10FFFF。十六进制转化为十进制即为codepoint值。在Java中还有个codeunit的概念。

Unicode目前实际使用的编码方式为UCS-2,一个字符占用两个字节。能够涵盖Unicode全部字符的为UCS-4,一个字符占用四个字节。

UTF-8

UTF-8为Unicode的一种实现方式,是一种变长编码。其编码规则为:






codepoint Unicode UTF-8
0 - 127 U-0000 0000 - U-0000 007F 0xxxxxxx
128 - 2047 U-0000 0080 - U-0000 07FF 110xxxxx 10xxxxxx
2048 - 65535 U-0000 0800 - U-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
65536 - 1114111 U-0001 0000 - U-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

xx部分为codepoint二进制值依次填写,不足的位补0。

UTF-16

UTF-16是Unicode的另一种实现方式,有UTF-16 BE和UTF-15 LE两种,为了区分,在UTF-16 BE前添加FF FE,在UTF-16 LE前添加FE FF。在windows和linux中一般使用LE。
编码规则:

  • U+0000 - U+FFFF:UTF-16对应的是其codepoint
  • U-0001 0000 - U-0010 FFFF:
  1. 码位减去0x10000,得到的值的范围为20比特长的0..0xFFFFF.
    高位的10比特的值(值的范围为0..0x3FF)被加上0xD800得到第一个码元或称作高位代理(high surrogate),值的范围是0xD800..0xDBFF.由于高位代理比低位代理的值要小,所以为了避免混淆使用,Unicode标准现在称高位代理为前导代理(lead surrogates)。
  2. 低位的10比特的值(值的范围也是0..0x3FF)被加上0xDC00得到第二个码元或称作低位代理(low surrogate),现在值的范围是0xDC00..0xDFFF.由于低位代理比高位代理的值要大,所以为了避免混淆使用,Unicode标准现在称低位代理为后尾代理(trail surrogates)。

U-0001 0000 - U-0010 FFFF未验证,来自UTF-16

Java使用的编码方式是UTF-16

UTF-32

UTF-32差不多等于UCS-4,UTF-16差不多等于UCS-2


----------

汉字“一”

CJK Unified Ideographs,中日韩统一表意文字,范围
U+4E00-U+9FFF。“一”是其中的第一个字符,对应的Unicode为U+4E00

  • 其UTF-8编码:因为U+4E00U+0800 - U+FFFF的范围中,所以UTF-8需要用三个字节去表示。其codepoint为19968,化为二进制为100 1110 0000 0000,填写至1110xxxx 10xxxxxx 10xxxxxx,为11100100 10111000 10000000
  • 其UTF-16编码:因为U+4E00U+0000- U+FFFF范围中,所以其UTF-16为0100 1110 0000 0000


Java中String类的getBytes()方法

1、UTF-16编码

String s = "一";
byte[] b = s.getBytes("UTF-16");
System.out.println("b.length: " + b.length);
for (int i = 0; i < b.length; i++) {
    System.out.print("b[" + i + "]: " + b[i]);
}

一个汉字占用两个byte,那么很显然b.length = 2b[0] = 78b[1] = 0,再看看编译器输出的结果:

b.length: 4
b[0]: -2
b[1]: -1
b[2]: 78
b[3]: 0

@@!和预期的不大一样。再看看-2和-1,其实它们分别是FE FF的十进制形式,因为前面有说到UTF-16有两种编码形式BELE,而FE FF代表的是LE

String s = "一丁";
byte[] b = s.getBytes("UTF-16");
System.out.println("b.length: " + b.length);
for (int i = 0; i < b.length; i++) {
    System.out.println("b[" + i + "]: " + b[i]);
}

“丁”是“一”后面的字符,再看看结果:

b.length: 6
b[0]: -2
b[1]: -1
b[2]: 78
b[3]: 0
b[4]: 78
b[5]: 1



2、UTF-8

String s = "一";
byte[] b = s.getBytes("UTF-8");
System.out.println("b.length: " + b.length);
for (int i = 0; i < b.length; i++) {
    system.out.println("b[" + i + "]: " + b[i]);
}

“一”在UTF-8中占用三个字节

b.length: 3
b[0]: -28
b[1]: -72
b[2]: -128

其中-2811100100的有符号十进制形式,-7210111000-12810000000


参考:

http://www.cnblogs.com/kingcat/archive/2012/10/16/2726334.html
https://zh.wikipedia.org/wiki/Unicode



2015/12/4 17:13:16