Chinaunix首页 | 论坛 | 博客
  • 博客访问: 645469
  • 博文数量: 108
  • 博客积分: 3236
  • 博客等级: 中校
  • 技术积分: 906
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-04 21:23
文章分类

全部博文(108)

文章存档

2011年(33)

2010年(75)

我的朋友

分类: LINUX

2010-06-29 20:53:15

字符编码类型
 
   英文字符,使用ASCII,用一个byte表示即可.ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
   汉字用一个byte来表示明显不够,因此最早的汉字编码,是采用两个byte来表示.同时为了与原来ascii英文字符不混淆.特别规定:
     两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。 这个方案称为GB2312编码.一般称为国标码.
    在计算机在中国开始普及年代,如DOS/WIN3.1/win95等阶段.GB2312立下了汗马功劳.在同一时期,以繁体字为主的台湾也搞一套类似的编码,称为BIG5编码.原理是一样的,但是与GB2312码有冲突.
  
    但是GB2312.还有很多缺点,一是字符集太小,只能表示几千个常用汉字.大量汉字没法表示,二是其它汉字表示集BIG5有冲突,经常出现乱码的情况.三是如果出现几种文字需要同时显示,如阿拉伯文,泰文等无法实现.这种情况在互联网时代尤其明显.
 
UNICODE
 
    为了解决全世界文字冲突问题,ISO把所有常用语言的字符,全部统一编码,称为"Universal Multiple-Octet Coded Character Set",简称 UCS,或称UNICODE方案.
  它规定所有字符包括英文字符由2个字节表示.但为了的兼容.原来的ASCII码高位字节全部采用0,低位就是原来ASCII值. 
   
   需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。我们一般称为UNICODE表示,是指用两个byte来,即一个Short来表示的方法.2个字节在32位CPU上正好是一个short型,这样在不同字节序的CPU下,同一个编码有两种排序,默认是小端字节序.也有按大端字节序,两种方案分别称为 Unicode,Unicode-Big.
     这样就造成一个编码有多种存储方式,这样造成推广的不便.
 
  UNICODE 在制订时没有考虑与任何一种现有的编码方案保持兼容,这使得 GBK 与UNICODE 在汉字的内码编排上完全是不一样的,没有一种简单的算术方法可以把文本内容从UNICODE编码和另一种编码进行转换,这种转换必须通过查表来进行.
 
  
  
UTF-8
随着互联网兴起,如何在网络上传输字符UNICODE也是一个问题.于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF8就是每次8个位传输数据,而 UTF16就是每次16个位,
 

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,还是以汉字“严”为例,演示如何实现UTF-8编码。

已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

 
GBK
    GBK编码(Chinese Internal Code Specification)是中国大陆制订的、等同于UCS的新的中文编码扩展国家标准。gbk编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,gbk是兼容gb2312编码的。GBK工作小组于1995年10月,同年12月完成GBK规范。该编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。Windows95/98简体中文版的字库表层编码就采用的是GBK,通过GBK与UCS之间一一对应的码表与底层字库联系。
 
  一般有时把ASCII与GB2312混排称为ANSI,它与UTF-8,UNICODE,UNICODE BIG称为四种编码.
 
WINDOW的记事本支持四种编码汉字
  
 
 
文本文件类型
   因为并存好几种编码,软件处理文本文件是如何判断类型的?实际如果不加一些附加信息,软件也难判断文本是哪一种格式.一般是文件前面加入BOM(Byte Order Mark)码.其中有下表.
Bytes Encoding Form
00 00 FE FF        UTF-32, big-endian
FF FE 00 00        UTF-32, little-endian
FE FF        UTF-16, big-endian/即一般的UNICODE-BIG
FF FE        UTF-16, little-endian/即UNICODE
EF BB BF        UTF-8
 
这样只要打开文本文件内容,查看0-3 byte是否这一些数字,即判断出是哪一种格式.如果全部都不是,意味着是ANSI编码.
 
关于BOM,更详细参见
 
一些编码格式一般是约定成俗的,如*.lrc,往往使用ASCII与GB码混排,即ANIS格式.C源程序采用ASCII.但中间的汉字在不同系统下有不同规定LINUX采用UTF-8,WINDOWS采用GB码.
 
 
Windows/Unix 文本回车符.
 
   处理文本文件还有一个细节,是WINDOWS的每行回车符两个字符,\r\n,而UNIX回车符一个字符是\n,而它还有一个特殊规定,最后一行是空行,即\n\n结尾.大部分软件能识别两种格式,但是WINDOWS记事本打开LINUX文本文件时,并不换行而是显示黑框.
   但fgets之类实现是最早在UNIX实现,所有读出来最后的字符都是\n,WINDOWS上也是如此.必须用fopen(name,"rb")然后用fread才能读出\r\n来.
  
标装C宽字节类型
  strlen(),计算结果只针对ASCII有效,对于2个BYTE字节无法处理.因此标准C中,制定了wchar_t,它一般被定义成unsigned short 型.对宽字节的函数要采用新的w打头的接口.
如求宽字符字符串的长度的函数是
#include
size_t wcslen(const wchar_t *s);
 
Linux 下汉字处理
 
   Linux 下的汉字编码是以UTF-8,这从RHEL的中文版的语言就可以知道,中文环境下,环境变量LANG的值为 zh_CN.UTF8,而WINDOWS自WINDOWS NT开始,内部都采用UNICODE表示.因此两者在编程有着细微差别.
   如果是带汉字的文本可参考相应的BOM来处理.但是在显示,打印时要因应不同的系统采用不同格式.
   如LINUX下控制台下,需要UTF-8格式才能正确处理.象SDL的图形界面下,汉字要转成UNICODE或UTF-8才能正常显示.文本文件还好处理.
   但如果在C代码里出现汉字常量
   如printf("黄新宇\n");,这个有不同的情况.如果这个C代码是在LINUX编辑,则C源程序中是UTF-8直接可以显示,如果这个C代码是在WINDOWS编辑拷贝过来.则很有可能是GB码,这样程序编译后在LINUX控制台上乱码.
  
 
  putty 下汉字显示,需要将字体换成UTF-8才能正常显示
 
另外LINUX中文文件名也是UTF-8编码的,可以在fopen中直接采用中文编码.如果WINDWOS的中文则有可能是UNICODE编码,但在samba拷贝后会自动转换
阅读(3294) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~