字符编码问题

来源:互联网 发布:存储数据的最小单位 编辑:程序博客网 时间:2024/05/20 00:12
用比较简单的话来说就是,Unicode定义了所有可以用来表示字符的数值集合(称之为Code Point)。UTF-8和UTF-16等UTF标准定义了这些数值和字符的映射关系。

ASCII字符集:
英文字母再加一些其他标点字符之类的也不会超过256个.一个字节表示者足够了

ISO 定义任何一个字符只对应一个确定的数字即 UCS(Universal Character Set) -- Unicode

其实Unicode涉及到两个步骤,首先是定义一个规范,给所有的字符指定一个唯一对应的数字,这完全是数学问题,可以跟计算机没半毛钱关系.第二步才是怎么把字符对应的数字保存在计算机中,这才涉及到实际在计算机中占多少字节空间.

     所以我们也可以这样理解,Unicode是用0至65535之间的数字来表示所有字符.其中0至127这128个数字表示的字符仍然跟ASCII完全一样.65536是2的16次方.这是第一步.第二步就是怎么把0至65535这些数字转化成01串保存到计算机中.这肯定就有不同的保存方式了.于是出现了UTF(unicode transformation format),有UTF-8,UTF-16. ----- 终于明白原来是这么个意义(UCS只是规定如何编码,并没有规定如何传输、保存这个编码)。


UTF-8
最大的优势是,没有字节序的概念。所以特别适合用于字符串的网络数据传输,不用考虑大小端问题。
UTF-8编码格式下,劣势是一个汉字需要至少3个char才能表示、一个汉字需要至少3个char来表示,也让汉字在网络传输上存在劣势,占用太多流量。

UTF-16 、 UTF-32
劣势:一致性,排序,网络传输任何字符对应的数字都用两个或四个字节来保存。

文件的开头几个字节就是标志表示存储方式:

EF BB BF    UTF-8
FE FF     UTF-16/UCS-2, little endian
FF FE     UTF-16/UCS-2, big endian
FF FE 00 00  UTF-32/UCS-4, little endian
00 00 FE FF  UTF-32/UCS-4, big-endian

Unicode和UTF-8之间的转换详解

    Unicode是一个字符集,而UTF-8是Unicode的其中一种,Unicode是定长的都为双字节,而UTF-8是可变的,对于汉字来说Unicode 占有的字节比UTF-8占用的字节少1个字节。Unicode为双字节,而UTF-8中汉字占三个字节。
    UTF-8编码字符理论上可以最多到6个字节长,然而16位BMP(Basic Multilingual Plane)字符最多
   只用到3字节长。

下面看一下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 


    xxx 的位置由字符编码数的二进制表示的位填入, 越靠右的 x 具有越少的特殊意义,只用最短
的那个足够表达一个字符编码数的多字节串。 注意在多字节串中, 第一个字节的开头"1"的数目
就是整个串中字节的数目。而第一行中以0开头,是为了兼容ASCII编码,为一个字节,第二行
就为双字节字符串,第三行为3字节,如汉字就属于这种,以此类推。(个人认为:其实我们
可以简单的把前面的1的个数看成字节数)
                         
    为了要将Unicode转换为UTF-8,当然要知道他们的区别到底在什么地方。下面来看一下,在Unicode
中的编码是怎样转换成UTF-8的,在UTF-8中,如果一个字符的字节小于0x80(128)则为ASCII字符,
占一个字节,可以不用转换,因为UTF-8兼容ASCII编码。假如在Unicode中汉字“你”的编码为“u4F60”,
把它转换为二进制为100111101100000,然后按照UTF-8的方法进行转换。
可以将Unicode二进制从低位往高位取出二进制数字,每次取6位(其中高两位由utf-8编码表填充),
如上述的二进制就可以分别取出为如下所示的格式,前面按格式填补,不足8位用0填补。
       
       unicode: 100111101100000                            4F60
         utf-8:    11100100,10111101,10100000       E4BDA0

    从上面就可以很直观的看出Unicode到UTF-8之间的转换,当然知道了UTF-8的格式后,就可以
进行逆运算,就是按照格式把它在二进制中的相应位置上取出,然后在转换就是所得到的Unicode字符了
(这个运算可以通过“位移”来完成)。

移位代码处理:

Unicode到UTF-8的转换(查看UTF-8编码表即可得知):
const wchar_t pUnicode = L"你";
char utf8[3+1];
memset(utf8,0,4);
utf8[0] = 0xE0|(pUnicode>>12);
utf8[1] = 0x80|((pUnicode>>6)&0x3F);
utf8[2] = 0x80|(pUnicode&0x3F);
utf8[3] = "\0";
//char[4]就是UTF-8的字符“你”了。 

UTF-8到Unicode的转换:
//UTF-8格式的字符串
const char* utf8 = "你";
wchar_t unicode;
unicode = (utf8[0] & 0x1F) << 12;
unicode |= (utf8[1] & 0x3F) << 6;
unicode |= (utf8[2] & 0x3F);
//unicode is ok!

为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5

GB2312 一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE、GB2312支持的汉字太少

GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符

GB2312、GBK都属于双字节字符集 (DBCS)。

GB18030 该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字

对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字节,用两个字节表示一个汉字。这两个字节的顺序是固定的,不受CPU字节序的影响。

Linux下libiconv库的安装和使用:

1.编译安装libiconv库

包的下载页面http://www.gnu.org/software/libiconv/

$ ./configure --prefix=/usr/local

$ make

$ make install

2.在/usr/local/lib/目录下拷备需要的库文件libcharset.so.1, libiconv.so.2。


1 0
原创粉丝点击