UTF-8编码

介绍 UTF-8 编码

UTF-8 是一种针对 Unicode 的可变长度字符编码。

针对 Unicode:UTF-8 是 Unicode 的实现方式之一。相当于 Unicode 规定了字符对应的代码值,这个代码值需要转换为字节序列的形式,用于数据存储、传输。代码值到字节序列的转换工作由 UTF-8 来完成。

可变长度字符编码:UTF-8 使用一至四个字节对 Unicode 字符集中的所有有效代码点进行编码。

  • UTF-8 使用 1 个字节表示 ASCII 字符;
  • UTF-8 使用 2 个字节表示带有附加符号的拉丁文、希腊文等;
  • UTF-8 使用 3 个字节表示其他基本多文种平面(BMP)中的字符(包含了大部分常用字,如大部分的汉字);
  • UTF-8 使用 4 个字节表示 Unicode 辅助平面的字符。

技术是为了解决问题而生的,UTF-8 编码是为了解决什么问题而设计的呢?UTF-8 是为了兼容 ASCII 编码而设计的。

ASCII 编码使用 1 个字节表示 ASCII 字符,而 Unicode 最初规定使用 2 个字节来表示所有的 Unicode 字符。如果使用 2 个字节来表示 ASCII 字符的话,那么含有大量 ASCII 字符的文本将浪费大量的存储空间。

UTF-8 编码使用 1 个字节来表示 ASCII 字符,而且字面与 ASCII 码的字面一一对应,这使得原来处理 ASCII 字符的软件无须或只须做少部分修改,即可继续使用。

UTF-8 编码的规则

Unicode 和 UTF-8 之间的转换关系表(x 字符表示码点占据的位)

码点的位数 码点起值 码点终值 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
7 U+0000 U+007F 1 0xxxxxxx
11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
image-20230124102710527.png

UTF-8 编码的规则:

  • 在 ASCII 码范围内的代码点,UTF-8 使用 1 个字节表示。
  • 大于 ASCII 码范围的代码点,UTF-8 使用多个字节表示。UTF-8 使用第一个字节的前几位表示该 Unicode 字符的字节长度(第一个字节的开头 1 的数目就是该 Unicode 字符的字节长度),其余字节的前两位固定为 10,作为标记
    • 如果第一个字节的前<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)

image-20230124160453248.png

通过 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"

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)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容