UTF-8
(8位元,Universal Character Set/Unicode Transformation Format
)是针对Unicode
的一种可变长度字符编码。它可以用来表示Unicode
标准中的任何字符,而且其编码中的第一个字节仍与ASCII
相容,使得原来处理ASCII
字符的软件无须或只进行少部份修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。
发展历程
在所有字符集中,最知名的可能要数被称为ASCII
的8位字符集了。它是美国标准信息交换代码(American Standard Code for Information Interchange
)的缩写, 为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成。
但是,由于它是针对英语设计的,当处理带有音调标号(形如汉语的拼音)的亚洲文字时就会出现问题。因此,创建出了一些包括256个字符的由ASCII
扩展的字符集。其中有一种通常被称为IBM字符集,它把值为128-255
之间的字符用于画图和画线,以及一些特殊的欧洲字符。另一种8位字符集是ISO 8859-1Latin 1
,也简称为ISOLatin-1
。它把位于128-255之间的字符用于拉丁字母表中特殊语言字符的编码,也因此而得名。欧洲语言不是地球上的唯一语言,因此亚洲和非洲语言并不能被8位字符集所支持。仅汉语字母表(或pictograms)就有80000以上个字符。但是把汉语、日语和越南语的一些相似的字符结合起来,在不同的语言里,使不同的字符代表不同的字,这样只用2个字节就可以编码地球上几乎所有地区的文字。因此,创建了UNICODE
编码。它通过增加一个高字节对ISO Latin-1
字符集进行扩展,当这些高字节位为0时,低字节就是ISO Latin-1
字符。UNICODE
支持欧洲、非洲、中东、亚洲(包括统一标准的东亚象形汉字和韩国表音文字)。但是,UNICODE
并没有提供对诸如Braille(盲文),Cherokee, Ethiopic(埃塞俄比亚语), Khmer(高棉语), Mongolian(蒙古语), Hmong(苗语), Tai Lu, Tai Mau文字的支持。同时它也不支持如Ahom(阿霍姆语), Akkadian(阿卡德语), Aramaic(阿拉米语), Babylonian Cuneiform(古巴比伦楔形文字), Balti(巴尔蒂语), Brahmi(婆罗米文), Etruscan(伊特拉斯坎语), Hittite(赫梯语/西台语), Javanese(爪哇语),Numidian(努米底亚语), Old Persian Cuneiform(古波斯楔形文字),Syrian(叙利亚语)之类的古老文字。
事实证明,对可以用ASCII
表示的字符使用UNICODE
并不高效,因为UNICODE
比ASCII
占用大一倍的空间,而对ASCII
来说高字节的0
对他毫无用处。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF(Unicode Transformation Format)
。常见的UTF格式有:UTF-7, UTF-7.5, UTF-8,UTF-16
, 以及 UTF-32
。
基本特征
UCS
字符U+0000
到U+007F
(ASCII)被编码为字节0×00
到0x7F
(ASCIⅡ
兼容)。这意味着只包含7位ASCIl
字符的文件在ASCIⅡ
和UTF-8
两种编码方式下是一样的。
所有大于0x007F
的UCS
字符被编码为一个有多个字节的串,每个字节都有标记位集。因此,ASCIl
字节(0x00-0x7F
)不可能作为任何其他字符的一部分。表示非ASCIl
字符的多字节串的第一个字节总是在0xC0
到0XFD
的范围里,并指出这个字符包含多少个字节。多字节串的其余字节都在0x80
到0xBF
范围里。这使得重新同步非常容易,并使编码无国界,且很少受丢失字节的影响。
UTF-8
编码字符理论上可以最多到6个字节长,然而16位BMP
字符最多只用到3字节长,Bigendian UCS-4
字节串的排列顺序是预定的,字节0xFE
和0xFF
在UTF-8
编码中从未用到。
编码字节数
UTF-8
使用1~4字节为每个字符编码:
·一个US-ASCIl
字符只需1字节编码(Unicode
范围由U+0000~U+007F
)。
·带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文等字母则需要2字节编码(Unicode
范围由U+0080~U+07FF
)。
·其他语言的字符(包括中日韩文字、东南亚文字、中东文字等)包含了大部分常用字,使用3字节编码。
·其他极少使用的语言字符使用4字节编码。
字符集
UTF-8
编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。UTF-8
转换表表示如下:
表一 UTF-8转换表
Unicode/UCS-4 | bit数 | UTF-8 | byte数 | 备注 |
---|---|---|---|---|
0000 ~ | 0~7 | 0XXX XXXX | 1 | |
007F | ||||
0080 ~ | 8~11 | 110X XXXX | 2 | |
07FF | 10XX XXXX | |||
0800 ~ | 12~16 | 1110 XXXX | 3 | 基本定义范围:0~FFFF |
FFFF | 10XX XXXX | |||
10XX XXXX | ||||
1 0000 ~ | 17~21 | 1111 0XXX | 4 | Unicode6.1定义范围:0~10 FFFF |
1F FFFF | 10XX XXXX | |||
10XX XXXX | ||||
10XX XXXX | ||||
20 0000 ~ | 22~26 | 1111 10XX | 5 | 说明:此非unicode编码范围,属于UCS-4 编码 |
3FF FFFF | 10XX XXXX | 早期的规范UTF-8可以到达6字节序列,可以覆盖到31位元(通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中 | ||
10XX XXXX | ||||
10XX XXXX | ||||
10XX XXXX | ||||
400 0000 ~ | 27~31 | 1111 110X | 6 | |
7FFF FFFF | 10XX XXXX | |||
10XX XXXX | ||||
10XX XXXX | ||||
10XX XXXX | ||||
10XX XXXX |
实际表示ASCII
字符的UNICODE
字符,将会编码成1个字节,并且UTF-8
表示与ASCII
字符表示是一样的。所有其他的UNICODE
字符转化成UTF-8
将需要至少2个字节。每个字节由一个换码序列开始。第一个字节由唯一的换码序列,由n位连续的1加一位0组成, 首字节连续的1的个数表示字符编码所需的字节数。
Unicode
转换为UTF-8
时,可以将Unicode
二进制从低位往高位取出二进制数字,每次取6位,如上述的二进制就可以分别取出为如下示例所示的格式,前面按格式填补,不足8位用0填补。
注:Unicode
转换为UTF-8
需要的字节数可以根据这个规则计算:如果Unicode
小于0X80
(Ascii
字符),则转换后为1个字节。否则转换后的字节数为Unicode
二进制位数+3再除以5。
示例
UNICODE uCA(1100 1010)
编码成UTF-8
将需要2个字节:
uCAC3 8A
, 过程如下:
uCA(1100 1010)
处于0080 ~07FF
之间,从上文中的转换表可知对其编码需要2bytes
,即两个字节,其对 应 UTF-8
格式为: 110X XXXX10XX XXXX
。从此格式中可以看到,对其编码还需要11位,而uCA(1100 1010)
仅有8位,这时需要在其二进制数前补0凑成11位: 000 1100 1010
, 依次填入110X XXXX 10XX XXXX
的空位中, 即得 1100 0011 1000 1010(C38A)
。
同理,UNICODE uF03F (1111 0000 0011 1111)
编码成UTF-8
将需要3个字节:
u F03FEF 80 BF
,对应格式为:1110XXXX10XX XXXX10XX XXXX
,编码还需要16位,将1111 0000 0011 1111(F03F)
依次填入,可得 1110 1111 1000 0000 1011 1111(EF 80 BF)
。
优缺点
优点
UTF-8
编码可以通过屏蔽位和移位操作快速读写。字符串比较时strcmp()
和wcscmp()
的返回结果相同,因此使排序变得更加容易。字节FF和FE在UTF-8
编码中永远不会出现,因此他们可以用来表明UTF-16
或UTF-32
文本(见BOM) UTF-8
是字节顺序无关的。它的字节顺序在所有系统中都是一样的,因此它实际上并不需要BOM
。
缺点
你无法从UNICODE
字符数判断出UTF-8
文本的字节数,因为UTF-8
是一种变长编码它需要用2个字节编码那些用扩展ASCII
字符集只需1个字节的字符 ISO Latin-1
是UNICODE
的子集,但不是UTF-8
的子集 8位字符的UTF-8
编码会被email
网关过滤,因为internet
信息最初设计为7位ASCII
码。因此产生了UTF-7
编码。 UTF-8
在它的表示中使用值100xxxxx
的几率超过50%
, 而现存的实现如ISO 2022, 4873, 6429
, 和8859
系统,会把它错认为是C1 控制码。因此产生了UTF-7.5
编码。
修正更新
java
使用UTF-16
表示内部文本,并支持用于字符串串行化的非标准的修正UTF-8
编码。标准UTF-8
和修正的UTF-8
有两点不同:
-
修正的
UTF-8
中,null
字符编码成2个字节(1100000010000000
)而不是标准的1个字节(00000000
),这样做可以保证编码后的字符串中不会嵌入null
字符。因此如果在类C语言中处理字符串,文本不会在第一个null
字符时截断(C字符串以’\0
'结尾)。 -
在标准
UTF-8
编码中,超出基本多语言范围(BMP-Basic Multilingual Plane
)的字符被编码为4字节格式,但是在修正的UTF-8
编码中,他们由代理编码对(surrogatepairs
)表示,然后这些代理编码对在序列中分别重新编码。结果标准UTF-8
编码中需要4个字节的字符,在修正后的UTF-8
编码中将需要6个字节。