- 如果第一个字节的前<u>两</u>位为 1,第三位为 0(110xxxxx),则表示 UTF-8 使用 2 个字节表示该 Unicode 字符;
- 如果第一个字节的前<u>三</u>位为 1,第四位为 0(1110xxxx),则表示 UTF-8 使用 3 个字节表示该 Unicode 字符;
- 依此类推;
- 如果第一个字节的前<u>六</u>位为 1,第七位为 0(1111110x),则表示 UTF-8 使用 6 个字节表示该 Unicode 字符;
UTF-8 编码的字节含义:对于 UTF-8 编码中的任意字节 B:
- 如果 B 的第一位为 0(0xxxxxxx),则 B 独立的表示一个 ASCII 字符;
- 如果 B 的第一位为 1,第二位为 0(10xxxxxx),则 B 为一个多字节表示的字符中的一个字节;
- 如果 B 的前二 / 三 / 四 / 五 / 六位为 1,其余位为 0,则 B 为二 / 三 / 四 / 五 / 六个字节表示的字符中的第一个字节。
UTF-8 编码示例
Unicode/UTF-8-character table (utf8-chartable.de)
通过 UTF-8 编码表,我们可以看到中文字符 “一” 的 Unicode 代码点为 "U 4E00",UTF-8 编码结果为 "e4 b8 80",
对中文字符 “一” 进行 UTF-8 编码,是如何得到 "e4 b8 80" 的呢?我们下面来看。
"4E00" 的二进制表示为 "0100 1110 0000 0000"。
UTF-8 使用 3 个字节表示常用的汉字,因此中文字符对应的字节序列格式为:"1110xxxx 10xxxxxx 10xxxxxx"
于是中文字符 “一” 的 UTF-8 编码结果为 "1110<u>0100</u> 10<u>111000</u> 10<u>000000</u>",它的十六进制表示为 "e4 b8 80"
代码语言:java复制public static void main(String[] args) throws UnsupportedEncodingException {
byte[] bytes = "一".getBytes("UTF-8");
// [-28, -72, -128]
System.out.println(Arrays.toString(bytes));
}
UTF-8 编码的优劣局限
UTF-8 编码的优点
UTF-8 和 ASCII 兼容:ASCII 是 UTF-8 的一个子集。因为一个纯 ASCII 字符串也是一个合法的 UTF-8 字符串,所以现存的 ASCII 文本不需要转换。为传统的扩展 ASCII 字符集设计的软件通常可以不经修改或很少修改就能与 UTF-8 一起使用。
任何面向字节的字符串搜索算法都可以用于 UTF-8 的数据(只要输入仅由完整的 UTF-8 字符组成)。UTF-8 可以保证一个字符的字节序列不会包含在另一个字符的字节序列中。而有些比较旧的可变长度字符编码(如Shift JIS)没有这个特质,故它们的字符串搜索算法变得相当复杂。
UTF-8 字符串可以由一个简单的算法可靠地识别出来。由于 UTF-8 字节序列的设计,如果一个疑似为字符串的序列被验证为 UTF-8 编码,那么我们可以有把握地说它是 UTF-8 字符串。一个字符串在任何其它编码中表现为合法的 UTF-8 的可能性很低,可能性随着字符串长度的增长而减小。 举例说明,字符值 C0、C1、F5 至 FF 从来没有出现。为了更好的可靠性,可以使用正则表达式来统计非法过长和替代值(可以查看W3 FAQ: Multilingual Forms上的验证 UTF-8 字符串的正则表达式)。
UTF-8 编码可以通过屏蔽位 和 移位操作快速读写:屏蔽位是指将字节的高位置零,以便获取低位的值;移位操作是指将字节的低位移动到高位,以便获取高位的值。这样,可以快速读取和写入 UTF-8 编码的字符。
UTF-8 编码的缺点
UTF-8 编码不利于使用正则表达式进行读音检索
正则表达式可以进行很多高级的英文模糊检索。比如,a-h 表示 a 到 h 间的所有字母。
同样 GBK 编码的中文也可以这样利用正则表达式,比如在只知道一个字的读音而不知道怎么写的情况下,也可用正则表达式检索,因为 GBK 编码是按读音排序的。虽然正则表达式检索并未考虑中文的多音字,但是由于中文的多音字数量不多,不少多音字还是同音不同调类型的多音字,所以大多数情况下正则表达式检索是还可以接受的。
但是 Unicode 汉字不是按读音排序的,它是按部首排序,所以不利于用正则表达式进行读音检索。在只知道一个字的部首而不知道如何发音的情况下,UTF-8 可用正则表达式检索而 GBK 不行。
UTF-8 的 ASCII 字符只占用一个字节,比较节省空间,但是更多字符的 UTF-8 编码占用的空间就要多出1/2,特别是中文、日文和韩文(CJK)这样的方块文字,它们大多需要三个字节。
无法根据 Unicode 字符数判断出 UTF-8 文本占用的字节数。因为 UTF-8 是一种可变长度字符编码。
参考资料
UTF-8 - 维基百科,自由的百科全书 (wikipedia.org)
Unicode/UTF-8-character table (utf8-chartable.de)