一下是最近在网上的找的资料稍做整理的内容,也贴上来供大家参考,可能还有不对的地方,也可以指正。
关于字符集及编码方式的基础知识:
字符集简史:
在所有字符集中,最知名可能要数被称为ASCII的7位字符集了。它是美国信息交换标准委员会(American Standards Committee for Information Interchange)的缩写, 为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成。
但是,由于他是针对英语设计的,当处理带有音调标号(形如汉语的拼音)的欧洲文字时就会出现问题。因此,创建出了一些包括255个字符的由ASCII扩展的字符集。其中有一种通常被成为IBM字符集,它把值为128-255之间的字符用于画图和画线,以及一些特殊的欧洲字符。另一种8位字符集是ISO 8859-1 Latin 1,也简称为ISO Latin-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(Universal Transformation Format)。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32。本文讨论UTF-8字符集的基础。
UTF-8字符集
UTF意为通用字集转换格式(Universal Character Set Transformation Format),UTF这是为传输而设计的编码,UTF-8是Unicode的8位元格式。 UTF-8是UNICODE的一种变长字符编码,由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码UNICODE字符。如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节,而如果UNICODE字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但很少会遇到那样的UNICODE字符。
UFT-8转换表表示如下:
UNICODE编码(16进制) UTF-8字节流(二进制)
0x00000000 - 0x0000007F 0xxxxxxx
0x00000080 - 0x000007FF 110xxxxx 10xxxxxx
0x00000800 - 0x0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
0x00010000 - 0x001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0x00200000 - 0x03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0x04000000 - 0x7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
实际表示ASCII字符的UNICODE字符,将会编码成1个字节,并且UTF-8表示与ASCII字符表示是一样的。所有其他的UNCODE字符转化成UTF-8将需要至少2个字节。每个字节由一个换码序列开始。第一个字节由唯一的换码序列,由n位1加一位0组成。n位1表示字符编码所需的字节数。
示例:
UNICODE的: "CA "(11001010) 编码成UTF-8将需要2个字节: CA -> C3 8A
UNICODE的: "F03F " (11110000 00111111) 编码成UTF-8将需要3个字节:F03F -> EF 80 BF
译者注:由上分析可以看到,UNCODE到UTF-8的转换就是先把UNCODE的字符转换成二进制,再由低到高六位六位额的取,每取一个六位在着六位的前面加上10,就构成一个八位。知道取到最后剩余的高位补1。(但是如果UNCODE转换的二进制小于等于01111111,那么UTF-8就是这个编码,保持不变。)(本人修改)。
UTF-8编码的优点:
UTF-8编码可以通过屏蔽位和移位操作快速读写。字符串比较时strcmp()和wcscmp()的返回结果相同,因此使排序变得更加容易。字节FF和FE在UTF-8编码中永远不会出现,因此他们可以用来表明UTF-16或UTF-32文本(见BOM) UTF-8 是字节顺序无关的。它的字节顺序在所有系统中都是一样的,因此它实际上并不需要BOM。
UTF-8编码的缺点:
你无法从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编码。
修正的UTF-8:
java使用UTF-16表示内部文本,并支持用于字符串串行化的非标准的修正UTF-8编码。标准UTF-8和修正的UTF-8有两点不同:修正的UTF-8中,null字符编码成2个字节(11000000 00000000) 而不是标准的1个字节(00000000),这样作可以保证编码后的字符串中不会嵌入null字符。因此如果在类C语言中处理字符串,文本不会在第一个null字符时截断(C字符串以null结尾)。在标准UTF-8编码中,超出基本多语言范围(BMP - Basic Multilingual Plain)的字符被编码为4字节格式,但是在修正的UTF-8编码中,他们由代理编码对(surrogate pairs)表示,然后这些代理编码对在序列中分别重新编码。结果标准UTF-8编码中需要4个字节的字符,在修正后的UTF-8编码中将需要6个字节。
位序标志BOM:
BOM(Byte Order Mark)是一个字符,它表明UNICODE文本的UTF-16,UTF-32的编码字节顺序(高字节低字节顺序)和编码方式(UTF-8,UTF-16,UTF-32, 其中UTF-8编码是字节顺序无关的)。
Encoding Representation
UTF-8 EF BB BF
UTF-16 Big Endian FE FF
UTF-16 Little Endian FF FE
UTF-32 Big Endian 00 00 FE FF
UTF-32 Little Endian FF FE 00 00
UTF-8 C++ Encoding Sample
一下四个函数用C++实现了2个和4个字节的UNICODE <--> UTF-8的编码解码过程。
#define MASKBITS 0x3F
#define MASKBYTE 0x80
#define MASK2BYTES 0xC0
#define MASK3BYTES 0xE0
#define MASK4BYTES 0xF0
#define MASK5BYTES 0xF8
#define MASK6BYTES 0xFC
typedef unsigned short Unicode2Bytes;
typedef unsigned int Unicode4Bytes;
void UTF8Encode2BytesUnicode(std::vector < Unicode2Bytes > input,
std::vector < byte > & output)
{
for(int i=0; i < input.size(); i++)
{
// 0xxxxxxx
if(input[i] < 0x80)
{
output.push_back((byte)input[i]);
}
// 110xxxxx 10xxxxxx
else if(input[i] < 0x800)
{
output.push_back((byte)(MASK2BYTES | input[i] > > 6));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if(input[i] < 0x10000)
{
output.push_back((byte)(MASK3BYTES | input[i] > > 12));
output.push_back((byte)(MASKBYTE | input[i] > > 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
}
}
void UTF8Decode2BytesUnicode(std::vector < byte > input,
std::vector < Unicode2Bytes > & output)
{
for(int i=0; i < input.size();)
{
Unicode2Bytes ch;
// 1110xxxx 10xxxxxx 10xxxxxx
if((input[i] & MASK3BYTES) == MASK3BYTES)
{
ch = ((input[i] & 0x0F) < < 12) | (
(input[i+1] & MASKBITS) < < 6)
| (input[i+2] & MASKBITS);
i += 3;
}
// 110xxxxx 10xxxxxx
else if((input[i] & MASK2BYTES) == MASK2BYTES)
{
ch = ((input[i] & 0x1F) < < 6) | (input[i+1] & MASKBITS);
i += 2;
}
// 0xxxxxxx
else if(input[i] < MASKBYTE)
{
ch = input[i];
i += 1;
}
output.push_back(ch);
}
}
void UTF8Encode4BytesUnicode(std::vector < Unicode4Bytes > input,
std::vector < byte > & output)
{
for(int i=0; i < input.size(); i++)
{
// 0xxxxxxx
if(input[i] < 0x80)
{
output.push_back((byte)input[i]);
}
// 110xxxxx 10xxxxxx
else if(input[i] < 0x800)
{
output.push_back((byte)(MASK2BYTES | input[i] > 6));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if(input[i] < 0x10000)
{
output.push_back((byte)(MASK3BYTES | input[i] > > 12));
output.push_back((byte)(MASKBYTE | input[i] > > 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
else if(input[i] < 0x200000)
{
output.push_back((byte)(MASK4BYTES | input[i] > > 18));
output.push_back((byte)(MASKBYTE | input[i] > > 12 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] > > 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
else if(input[i] < 0x4000000)
{
output.push_back((byte)(MASK5BYTES | input[i] > > 24));
output.push_back((byte)(MASKBYTE | input[i] > > 18 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] > > 12 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] > > 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
else if(input[i] < 0x8000000)
{
output.push_back((byte)(MASK6BYTES | input[i] > > 30));
output.push_back((byte)(MASKBYTE | input[i] > > 18 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] > > 12 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] > > 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input[i] & MASKBITS));
}
}
}
void UTF8Decode4BytesUnicode(std::vector < byte > input,
std::vector < Unicode4Bytes > & output)
{
for(int i=0; i < input.size();)
{
Unicode4Bytes ch;
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
if((input[i] & MASK6BYTES) == MASK6BYTES)
{
ch = ((input[i] & 0x01) < < 30) | ((input[i+1] & MASKBITS) < < 24)
| ((input[i+2] & MASKBITS) < < 18) | ((input[i+3]
& MASKBITS) < < 12)
| ((input[i+4] & MASKBITS) < < 6) | (input[i+5] & MASKBITS);
i += 6;
}
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
else if((input[i] & MASK5BYTES) == MASK5BYTES)
{
ch = ((input[i] & 0x03) < < 24) | ((input[i+1]
& MASKBITS) < < 18)
| ((input[i+2] & MASKBITS) < < 12) | ((input[i+3]
& MASKBITS) < < 6)
| (input[i+4] & MASKBITS);
i += 5;
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
else if((input[i] & MASK4BYTES) == MASK4BYTES)
{
ch = ((input[i] & 0x07) < < 18) | ((input[i+1]
& MASKBITS) < < 12)
| ((input[i+2] & MASKBITS) < < 6) | (input[i+3] & MASKBITS);
i += 4;
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if((input[i] & MASK3BYTES) == MASK3BYTES)
{
ch = ((input[i] & 0x0F) < < 12) | ((input[i+1] & MASKBITS) < < 6)
| (input[i+2] & MASKBITS);
i += 3;
}
// 110xxxxx 10xxxxxx
else if((input[i] & MASK2BYTES) == MASK2BYTES)
{
ch = ((input[i] & 0x1F) < < 6) | (input[i+1] & MASKBITS);
i += 2;
}
// 0xxxxxxx
else if(input[i] < MASKBYTE)
{
ch = input[i];
i += 1;
}
output.push_back(ch);
}
}
阅读(754) | 评论(0) | 转发(0) |