UTF-8
字符集名称:UTF-8
UTF-8(8 位元 Universal Character Set/Unicode Transformation Format)是针对Unicode 的一种可变长度字符编码。它可以用来表示 Unicode 标准中的任何字符,而且其编码中的第一个字节仍与 ASCII 相容,使得原来处理 ASCII 字符的软件无需或只作少部份修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他储存或传送文字的应用中,优先采用的编码。
UTF-8 使用一至四个字节为每个字符编码:
- 128 个 US-ASCII 字符只需一个字节编码(Unicode 范围由 U+0000 至 U+007F)。
- 带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要二个字节编码(Unicode 范围由 U+0080 至 U+07FF)。
- 其他基本多文种平面(BMP)中的字符(这包含了大部分常用字)使用三个字节编码。
- 其他极少使用的 Unicode 辅助平面的字符使用四字节编码。
对上述提及的第四种字符而言,UTF-8 使用四个字节来编码似乎太耗费资源了。但 UTF-8 对所有常用的字符都可以用三个字节表示,而且它的另一种选择,UTF-16编码,对前述的第四种字符同样需要四个字节来编码,所以要决定 UTF-8 或 UTF-16 哪种编码比较有效率,还要视所使用的字符的分布范围而定。不过,如果使用一些传统的压缩系统,比如 DEFLATE,则这些不同编码系统间的的差异就变得微不足道了。若顾及传统压缩算法在压缩较短文字上的效果不大,可以考虑使用 Standard Compression Scheme for Unicode(SCSU)。
因特网工程工作小组(IETF)要求所有因特网协议都必须支援 UTF-8 编码。[1] 互联网邮件联盟(IMC)建议所有电子邮件软件都支援 UTF-8编码。所有主要的电子邮件软件中,只有 Eudora 不支援 UTF-8 编码。
历史
1992年初,为建立良好的字节串编码系统(byte-stream encoding)以供多字节字符集(multi-byte character sets)使用,开始了一个正式的研究。ISO/IEC 10646的初稿中有一个非必须的附录,名为UTF。当中包含了一个供32位元的字符使用的字节串编码系统。这个编码方式的性能并不令人满意,但它提出了将0-127的范围保留给ASCII以相容旧系统的概念。
1992年7月,X/Open委员会XoJIG开始寻求一个较佳的编码系统。UNIX 系统实验室(UNIX System Laboratories, USL)的Dave Prosser为此提出了一个编码系统的建议。它具备可更快速实作的特性,并引入一项新的改进。其中,7位元的ASCII符号只代表原来的意思,所有多字节序列则会包含第8位元的符号,也就是所谓的最高有效位元。
1992年8月,这个建议由IBMX/Open的代表流传到一些感兴趣的团体。与此同时,贝尔实验室Plan 9操作系统工作小组的肯·汤普逊对这编码系统作出重大的修改,让编码可以自我同步(self-synchronizing),使得不必从字串的开首读取,也能找出字符间的分界。1992年9月2日,汤普逊和Pike一起在美国新泽西州一架餐车的餐桌垫上描绘出此设计的要点。接下来的日子,Pike及汤普逊将它实现,并将这编码系统完全应用在Plan 9当中,及后他将有关成果回馈X/Open。
1993年1月25-29日的在圣地牙哥举行的USENIX会议首次正式介绍UTF-8。
自1996年起,微软的CAB(MS Cabinet)规格在UTF-8标准正式落实前就明确容许在任何地方使用UTF-8编码系统。但有关的编码器实际上从来没有实作这方面的规格。
描述
目前有好几份关于UTF-8详细规格的文件,但这些文件在定义上有些许的不同:
- RFC 3629 / STD 63(2003),这份文件制定了UTF-8是标准的因特网协议元素
- 第四版,The Unicode Standard,§3.9-§3.10(2003)
- ISO/IEC 10646-1:2000附加文件D(2000)
它们取代了以下那些被淘汰的定义:
- ISO/IEC 10646-1:1993修正案2/附加文件R(1996)
- 第二版,The Unicode Standard,附录A(1996)
- RFC 2044(1996)
- RFC 2279(1998)
- 第三版,The Unicode Standard,§2.3(2000)及勘误表#1:UTF-8 Shortest Form(2000)
- Unicode Standard 附加文件#27: Unicode 3.1(2001)
事实上,所有定义的基本原理都是相同的,它们之间最主要的不同是支援的字符范围及无效输入的处理方法。
Unicode字符的位元被分割为数个部分,并分配到UTF-8的字节串中较低的位元的位置。在U+0080的以下字符都使用内含其字符的单字节编码。这些编码正好对应7位元的ASCII字符。在其他情况,有可能需要多达4个字符组来表示一个字符。这些多字节的最高有效位元会设定成1,以防止与7位元的ASCII字符混淆,并保持标准的字节主导字串(standard byte-oriented string)运作顺利。
代码范围 |
标量值(scalar value) |
UTF-8 |
注释 |
---|---|---|---|
000000 - 00007F |
00000000 00000000 0zzzzzzz |
0zzzzzzz(00-7F) |
ASCII字符范围,字节由零开始 |
七个z |
七个z |
||
000080 - 0007FF |
00000000 00000yyy yyzzzzzz |
110yyyyy(C2-DF) 10zzzzzz(80-BF) |
第一个字节由110开始,接着的字节由10开始 |
三个y;二个y;六个z |
五个y;六个z |
||
000800 - 00D7FF |
00000000 xxxxyyyy yyzzzzzz |
1110xxxx(E0-EF) 10yyyyyy 10zzzzzz |
第一个字节由1110开始,接着的字节由10开始 |
四个x;四个y;二个y;六个z |
四个x;六个y;六个z |
||
010000 - 10FFFF |
000wwwxx xxxxyyyy yyzzzzzz |
11110www(F0-F4) 10xxxxxx 10yyyyyy 10zzzzzz |
由11110开始,接着的字节由10开始 |
三个w;二个x;四个x;四个y;二个y;六个z |
三个w;六个x;六个y;六个z |
- Note 1 Unicode在范围D800-DFFF中不存在任何字符,基本多文种平面中约定了这个范围用于UTF-16扩展标识辅助平面(两个UTF-16表示一个辅助平面字符). 当然,任何编码都是可以被转换到这个范围,但在unicode中他们并不代表任何合法的值。
例如,希伯来语字母 aleph (א)的Unicode代码是 U+05D0,按照以下方法改成 UTF-8:
- 它属于 U+0080到U+07FF区域,这个表说明它使用双字节, 110yyyyy 10zzzzzz.
- 十六进制 的 0x05D0换算成二进制就是 101-1101-0000.
- 这11位数按顺序放入"y"部分和"z"部分: 11010111 10010000.
- 最后结果就是双字节,用十六进制写起来就是 0xD7 0x90,这就是这个字符aleph (א)的UTF-8编码。
所以开始的128个字符(US-ASCII)只需一字节,接下来的1920个字符需要双字节编码,包括带变音符号的拉丁字母, 希腊字母, 西里尔字母, 科普特语字母, 亚美尼亚语字母, 希伯来文字母和阿拉伯字母的字符。基本多文种平面中其余的字符使用三个字节,剩余字符使用四个字节。
根据这种方式可以处理更大数量的字符。原来的规范允许长达6字节的序列,可以覆盖到31位元 (通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据这些规范,以下字节值将无法出现在合法 UTF-8序列中:
编码(二进制) |
编码(十六进制) |
注释 |
---|---|---|
1100000x |
C0, C1 |
过长编码:双字节序列的头字节,但码点<= 127 |
1111111x |
FE, FF |
无法达到: 7 或8字节序列的头字节 |
111110xx |
F8, F9, FA, FB, FC, FD |
被RFC 3629规范: 5 或 6字节序列的头字节 |
11110101 |
F5, F6, F7 |
被RFC 3629规范: 码点超过10FFFF的头字节 |
UTF-8的编码方式
UTF-8是UNICODE的一种变长度的编码表达方式 〈一般UNICODE为双字节(指UCS2)〉,它由Ken Thompson于1992年建立,现在已经标准化为RFC 3629。UTF-8就是以8位为单元对UCS进行编码,而UTF-8不使用大尾序和小尾序的形式,每个使用UTF-8储存的字符,除了第一个字节外,其余字节的头两个位元都是以 "10" 开始,使文字处理器能够较快地找出每个字符的开始位置。
但为了与以前的ASCII码相容 (ASCII为一个字节),因此 UTF-8 选择了使用可变长度字节来储存 Unicode:
UCS-2编码 |
UTF-8字节流 |
---|---|
U-00000000 – U-0000007F: |
0xxxxxxx |
U-00000080 – U-000007FF: |
110xxxxx 10xxxxxx |
U-00000800 – U-0000FFFF: |
1110xxxx 10xxxxxx 10xxxxxx |
U-00010000 – U-001FFFFF: |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
U-00200000 – U-03FFFFFF: |
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
U-04000000 – U-7FFFFFFF: |
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
-
- 在ASCII码的范围,用一个字节表示,超出ASCII码的范围就用字节表示,这就形成了我们上面看到的UTF-8的表示方法,这様的好处是当UNICODE文件中只有ASCII码时,储存的文件都为一个字节,所以就是普通的ASCII文件无异,读取的时候也是如此,所以能与以前的ASCII文件相容。
-
- 大于ASCII码的,就会由上面的第一字节的前几位表示该unicode字符的长度,比如110xxxxxx前三位的二进制表示告诉我们这是个 2BYTE的UNICODE字符;1110xxxx是个三位的UNICODE字符,依此类推;xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义.只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目.。
ASCII字母继续使用1字节储存,重音文字、希腊字母或西里尔字母等使用2字节来储存,而常用的汉字就要使用3字节。辅助平面字符则使用4字节。
在UTF-8文件的开首,很多时都放置一个U+FEFF字符 (UTF-8 以 EF,BB,BF 代表),以显示这个文字档案是以UTF-8编码。
UTF-8的特性
UTF-8 |
|
---|---|
Smallest code point |
0000 |
Largest code point |
10FFFF |
Code unit size |
8 bits |
Byte order |
N/A |
Minimal bytes/character |
1 |
Maximal bytes/character |
4 |
- UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容),这也意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
- 所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集。因此,ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分。
- 表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里,并指出这个字符包含多少个字节。多字节串的其余字节都在 0x80 到 0xBF 范围里,这使得重新同步非常容易,并使编码无国界,且很少受丢失字节的影响。
- 可以编入所有可能的 231个 UCS 代码
- UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长。
- Bigendian UCS-4 字节串的排列顺序是预定的。
- 字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到,同时,UTF-8以字节为编码单元,它的字节顺序在所有系统中都是一様的,没有字节序的问题,也因此它实际上并不需要BOM。
- 与 UTF-16 或其他 Unicode 编码相比,对于不支援 Unicode 和 XML 的系统,UTF-8 更不容易造成问题。
【注】
- UTF为UCS / Unicode Transformation Format“Unicode转换格式”的缩写。
- UCS的中文全称为:信息技术--通用多八位编码字符集 (Universal Multi-octet Coded Character Set),由ISO/IEC 10646 标准描述。