字符集与字符编码
我们平时说的ASCII码和Unicode指的都是字符集,而UTF-8则是字符集的编码方式。
字符集
字符集就是所能表示的范围集合,比如ASCII码的字符集可以表示256个字符,而Unicode的字符集则可以表示所有的语言和符号。
ASCII码,一共包含00000000~01111111
共128个字符,直接使用地址对应的二进制数来表示。比如字母A的地址是65,65的二进制就是01000001
,这个二进制数就是编码字符集中的一个元素。可以表示阿拉伯数字和大小写英文字母,以及一些简单的符号。可以看出ASCII码只需要1个字节的存储空间,最高位为0。
ASCII码能最多表示256个字符,是针对英文产生的,而面对中文、阿拉伯文之类的复杂文字,256个字符显然是不够用的。于是各个国家或组织都相继制定了符合自己语言文字的标准,比如gb2312、big5等等。
各种编码规范互不兼容,且只能表示自己需要的字符,于是,国际标准化组织(ISO)决定制定一套全世界通用的编码规范,这就是Unicode。Unicode包含了全世界所有的字符。
1)英文字符 ‘A’ 在ASCII码和Unicode码字符集中的元素表示
英文字符的Unicode码就是简单地在ASCII码前面添加一个00字节。
┌────┐
ASCII: │ 41 │
└────┘
┌────┬────┐
Unicode: │ 00 │ 41 │
└────┴────┘
2)中文字符 ‘中’ 在GB2312码和Unicode码字符集中的元素表示
┌────┬────┐
GB2312: │ d6 │ d0 │
└────┴────┘
┌────┬────┐
Unicode: │ 4e │ 2d │
└────┴────┘
字符编码
一般情况下,都是采用Unicode的字符集,使用UFT-8的编码方案进行存储。
UTF-8编码是Unicode的存储方式,会根据字符的大小自动变长存储,如果是英文字母就采用1个字节存储,如果是汉字则每个汉字需要占据3个字节。
1)Unicode字符集可以使用的编码方案有三种
Unicode是一个集合,包含了各国全部的字符。Unicode 可以使用的编码方案有三种,分别是:
- UFT-8:一种变长的编码方案,使用 1~6 个字节来存储;
- UFT-32:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;
- UTF-16:介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。
2)UTF-8编码
UTF-8编码是字符集的存储方式。因为英文字符的Unicode编码高字节总是00,包含大量英文的文本会浪费空间。所以,出现了UTF-8编码,它是一种变长编码,用来把固定长度的Unicode编码变成1~4字节的变长编码。通过UTF-8编码,英文字符 ‘A’ 的UTF-8编码变为0x41,正好和ASCII码一致,而中文 ‘中’ 的UTF-8编码为3字节0xe4b8ad。
UTF-8编码的另一个好处是容错能力强。如果传输过程中某些字符出错,不会影响后续字符,因为UTF-8编码依靠高字节位来确定一个字符究竟是几个字节,它经常用来作为传输编码。
Java中编码
始终牢记:Java的String和char在内存中总是以Unicode编码表示。
在Java中,char类型实际上就是两个字节的Unicode编码。我们可以把字符串转换成其他编码,转换编码后,就不再是char类型,而是byte类型表示的数组。
byte[] b1 = "Hello".getBytes(); // 按ISO8859-1编码转换,不推荐
byte[] b2 = "Hello".getBytes("UTF-8"); // 按UTF-8编码转换
byte[] b2 = "Hello".getBytes("GBK"); // 按GBK编码转换
byte[] b3 = "Hello".getBytes(StandardCharsets.UTF_8); // 按UTF-8编码转换
如果要把已知编码的byte[]转换为String,可以这样做:
byte[] b = ...
String s1 = new String(b, "GBK"); // 按GBK转换
String s2 = new String(b, StandardCharsets.UTF_8); // 按UTF-8转换
他の者にできたか?ここまでやれたか?この先できるか?いいや、仆にしかできない!