Chinaunix首页 | 论坛 | 博客
  • 博客访问: 429457
  • 博文数量: 83
  • 博客积分: 2622
  • 博客等级: 少校
  • 技术积分: 1345
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 08:59
个人简介

一直在努力

文章分类

全部博文(83)

文章存档

2014年(3)

2013年(9)

2012年(46)

2010年(25)

分类:

2010-08-30 20:12:12


一下是最近在网上的找的资料稍做整理的内容,也贴上来供大家参考,可能还有不对的地方,也可以指正。 

关于字符集及编码方式的基础知识: 

字符集简史: 
        在所有字符集中,最知名可能要数被称为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); 
      } 
阅读(750) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~