编写计算机程序时,为什么要把mysql 结果拼接字符串转变为字符串

收藏的版块
您还没有收藏版块 提示:收藏版块请点击列表页的
1 Pages: 1/2& & &Go
发表于: 22:05
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
unicode和ansi字符集
Unicode&& :宽字节字符集1. 如何取得一个既包含单字节字符又包含双字节字符的字符串的字符个数?可以调用Microsoft&& Visual&& C++的运行期库包含函数_mbslen来操作多字节(既包括单字节也包括双字节)字符串。调用strlen函数,无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。2. 如何对DBCS(双字节字符集)字符串进行操作?函数 描述PTSTR&& CharNext&& (&& LPCTSTR&& ); 返回字符串中下一个字符的地址PTSTR&& CharPrev&& (&& LPCTSTR,&& LPCTSTR&& ); 返回字符串中上一个字符的地址BOOL&& IsDBCSLeadByte(&& BYTE&& ); 如果该字节是DBCS字符的第一个字节,则返回非0值3. 为什么要使用Unicode?(1) 可以很容易地在不同语言之间进行数据交换。(2) 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。(3) 提高应用程序的运行效率。Windows&& 2000是使用Unicode从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。Windows&& CE&& 本身就是使用Unicode的一种操作系统,完全不支持ANSI&& Windows函数Windows&& 98&& 只支持ANSI,只能为ANSI开发应用程序。Microsoft公司将COM从16位Windows转换成Win32时,公司决定需要字符串的所有COM接口方法都只能接受Unicode字符串。4. 如何编写Unicode源代码?Microsoft公司为Unicode设计了WindowsAPI,这样,可以尽量减少代码的影响。实际上,可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。只需要定义两个宏(UNICODE和_UNICODE),就可以修改然后重新编译该源文件。_UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常必须同时定义这两个宏。5. Windows定义的Unicode数据类型有哪些?数据类型 说明WCHAR Unicode字符PWSTR 指向Unicode字符串的指针PCWSTR 指向一个恒定的Unicode字符串的指针对应的ANSI数据类型为CHAR,LPSTR和LPCSTR。ANSI/Unicode通用数据类型为TCHAR,PTSTR,LPCTSTR。6. 如何对Unicode进行操作?字符集 特性 实例ANSI 操作函数以str开头 strcpyUnicode 操作函数以wcs开头 wcscpyMBCS 操作函数以_mbs开头 _mbscpyANSI/Unicode 操作函数以_tcs开头 _tcscpy(C运行期库)ANSI/Unicode 操作函数以lstr开头 lstrcpy(Windows函数)所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版本函数结尾以W表示。Windows会如下定义:#ifdef&&&& UNICODE#define&&&& CreateWindowEx&&&& CreateWindowExW#else#define&&&& CreateWindowEx&&&& CreateWindowExA#endif&&&&&& //&& !UNICODE7. 如何表示Unicode字符串常量?字符集 实例ANSI “string”Unicode L“string”ANSI/Unicode T(“string”)或_TEXT(“string”)if(&& szError[0]&& ==&& _TEXT(‘J’)&& ){&& }8. 为什么应当尽量使用操作系统函数?这将有助于稍稍提高应用程序的运行性能,因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。如:StrCat,StrChr,StrCmp和StrCpy等。9. 如何编写符合ANSI和Unicode的应用程序?(1) 将文本串视为字符数组,而不是chars数组或字节数组。(2) 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。(3) 将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。(4) 将TEXT宏用于原义字符和字符串。(5) 执行全局性替换(例如用PTSTR替换PSTR)。(6) 修改字符串运算问题。例如函数通常希望在字符中传递一个缓存的大小,而不是字节。这意味着不应该传递sizeof(szBuffer),而应该传递(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters&& *sizeof(TCHAR)),而不是调用malloc(nCharacters)。10. 如何对字符串进行有选择的比较?通过调用CompareString来实现。标志 含义NORM_IGNORECASE 忽略字母的大小写NORM_IGNOREKANATYPE 不区分平假名与片假名字符NORM_IGNORENONSPACE 忽略无间隔字符NORM_IGNORESYMBOLS 忽略符号NORM_IGNOREWIDTH 不区分单字节字符与作为双字节字符的同一个字符SORT_STRINGSORT 将标点符号作为普通符号来处理11. 如何判断一个文本文件是ANSI还是Unicode?判断如果文本文件的开头两个字节是0xFF和0xFE,那么就是Unicode,否则是ANSI。12. 如何判断一段字符串是ANSI还是Unicode?用IsTextUnicode进行判断。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此,IsTextUnicode有可能返回不正确的结果。13. 如何在Unicode与ANSI之间转换字符串?Windows函数MultiByteToWideChar用于将多字节字符串转换成宽字符串;函数WideCharToMultiByte将宽字符串转换成等价的多字节字符串。到底什么是ANSI,什么是UNICODE呢?其实这是两种不同的编码方式标准,ANSI中的字符采用8bit,而UNICODE中的字符采用16bit。8bit的ANSI编码只能表示256种字符,表示26个英文字母是绰绰有余的,但是表示汉字,韩国语,日语等有着成千上万个字符的非西方字符肯定就不够了,正是如此才引入了UNICODE标准。两种不同的编码方式还是说通俗一点吧你的操作系统应该是中文的,如果你用记事本写了一段话,默认保存的是ANSI,你再打开看是没有问题的但是如果你把这个txt文件复制到一个日文的操作系统上看,就会发现都是乱码。这时候UNICODE优势就出来了,如果你当初保存的时候选择的是UNICODE,不管在什么语言的windows下面看,你的中文文档都能够正确地显示。但是用UNICODE会占用更多的字符。编码指不同国家的语言在计算机中的一种存储和解释规范 ANSI与ASCII &&&&&& 最初,Internet上只有一种字符集——ANSI的ASCII字符集(American Standard Code for Information Interchange, “美国信息交换标准码),它使用7 bits来表示一个字符,总共表示128个字符,后来IBM公司在此基础上进行了扩展,用8bit来表示一个字符,总共可以表示256个字符,充分利用了一个字节所能表达的最大信息 nANSI字符集:ASCII字符集,以及由此派生并兼容的字符集,如:GB2312,正式的名称为MBCS(Multi-Byte Chactacter System,多字节字符系统),通常也称为ANSI字符集。UNICODE与UTF8,UTF16 &&&&&&&& 由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,产生了Unicode字符集,它固定使用16 bits(两个字节)来表示一个字符,共可以表示65536个字符 &&&&&&&&标准的Unicode称为UTF-16(UTF:UCS Transformation Format )。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。(Unicode字符集有多种编码形式) 例如“连通”两个字的Unicode标准编码UTF-16 (big endian)为:DE 8F 1A 90&&&&&&&&&&&&&&&& 而其UTF-8编码为:E8 BF 9E E9 80 9A &&&&&&&&当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码:检测文件头标识,提示用户选择,根据一定的规则猜测最标准的途径是检测文本最开头的几个字节,开头字节 Charset/encoding,全称是:American National Standard Institute 中文译名: 美国国家标准协会为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。 不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 22:17
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
Unicode是什么?来源: wxiu.com 时间:
作者: fox  Unicode是什么?  Unicode是什么? 析Unicode和UTF-8  1. 各地的方言  首先说明一下现在常用的一些编码方案:  1. 在中国,大陆最常用的就是GBK18030编码,除此之外还有GBK,GB2312,这几个编码的关系是这样的。  n 最早制定的汉字编码是GB2312,包括6763个汉字和682个其它符号  n 95年重新修订了编码,命名GBK1.0,共收录了21886个符号。  n 之后又推出了GBK18030编码,共收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字,现在WINDOWS平台必需要支持GBK18030编码。  按照GBK18030、GBK、GB2312的顺序,3种编码是向下兼容,同一个汉字在三个编码方案中是相同的编码。  2. 台湾,香港等地使用的是BIG5编码  3. 日本:SJIS编码  2. Unicode  如果把各种文字编码形容为各地的方言,那么Unicode就是世界各国合作开发的一种语言。  在这种语言环境下,不会再有语言的编码冲突,在同屏下,可以显示任何语言的内容,这就是Unicode的最大好处。  那么Unicode是如何编码的呢?其实非常简单。  就是将世界上所有的文字用2个字节统一进行编码。可能你会问,2个字节最多能够表示65536个编码,够用吗?  韩国和日本的大部分汉字都是从中国传播过去的,字型是完全一样的。  比如:“文”字,GBK和SJIS中都是同一个汉字,只是编码不同而已。  那样,像这样统一编码,2个字节就已经足够容纳世界上所有的语言的大部分文字了。  UCS-2 与UCS-4  Unicode的学名是'Universal Multiple-Octet Coded Character Set',简称为UCS。  现在用的是UCS-2,即2个字节编码,而UCS-4是为了防止将来2个字节不够用才开发的。UCS-2也称为基本多文种平面。  UCS-2转换到UCS-4只是简单的在前面加2个字节0。  UCS-4则主要用于保存辅助平面,例如Unicode 4.0中的第二辅助平面  20000-20FFF - 21000-21FFF - 22000-22FFF - 23000-23FFF - 24000-24FFF - 25000-25FFF - 26000-26FFF - 27000-27FFF - 28000-28FFF - 29000-29FFF - 2A000-2AFFF - 2F000-2FFFF  总共增加了16个辅助平面,由原先的65536个编码扩展至将近100万编码。  3. 兼容codepage  那么既然统一了编码,如何兼容原先各国的文字编码呢?  这个时候就需要codepage了。  什么是codepage?codepage就是各国的文字编码和Unicode之间的映射表。  比如简体中文和Unicode的映射表就是CP936,点这里查看官方的映射表。  以下是几个常用的codepage,相应的修改上面的地址的数字即可。  codepage=936 简体中文GBK  codepage=950 繁体中文BIG5  codepage=437 美国/加拿大英语  codepage=932 日文  codepage=949 韩文  codepage=866 俄文  codepage=65001 unicode UFT-8  最后一个65001,据个人理解,应该只是一个虚拟的映射表,实际只是一个算法而已。  从936中随意取一行,例如:  0xABD #CJK UNIFIED IDEOGRAPH  前面的编码是GBK的编码,后面的是Unicode。  通过查这张表,就能简单的实现GBK和Unicode之间的转换。  4. UTF-8  现在明白了Unicode,那么UTF-8又是什么呢?又为什么会出现UTF-8呢?  ASCII转换成UCS-2,只是在编码前插入一个0x0。用这些编码,会包括一些控制符,比如 '' 或 '/',这在UNIX和一些C函数中,将会产生严重错误。因此可以肯定,UCS-2不适合作为Unicode的外部编码。  因此,才诞生了UTF-8。那么UTF-8是如何编码的?又是如何解决UCS-2的问题呢?  例:  E4 BD A00000  这是“你”字的UTF-8编码  4F
  这是“你”的Unicode编码  按照UTF-8的编码规则,分解如下:xxxx0100 xx111101 xx100000  把除了x之外的数字拼接在一起,就变成“你”的Unicode编码了。  注意UTF-8的最前面3个1,表示整个UTF-8串是由3个字节构成的。  经过UTF-8编码之后,再也不会出现敏感字符了,因为最高位始终为1。  以下是Unicode和UTF-8之间的转换关系表:  U- - U-0000007F: 0xxxxxxx  U- - U-000007FF: 110xxxxx 10xxxxxx  U- - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx  U- - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  U- - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  U- - U-7FFFFFFF: xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  Unicode编码转换到UTF-8,简单的把Unicode字节流套到x中就变成UTF-8了。
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 23:05
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
如果是记事本保存的txt文件,如果文件头没有编码信息,通常都是ASCII码如果存在编码信息,就根据编码信息解码记事本保存 Unicode 编码的文本,会在文件头加两个字节表示该文本文件是Unicode 编码,这两个字节内容16进制表示为 FF FE记事本保存 Unicode big endian 编码的文本,会在文件头加两个字节表示该文本文件是 Unicode big endian 编码,这两个字节内容16进制表示为FE FF记事本保存 UTF-8 编码的文本,会在文件头加三个字节表示该文本文件是UTF-8 编码,这三个字节内容16进制表示为 EF BB BF记事本保存 ASCII 编码的文本,不会在文件头加任何字节,直接存储 ASCII码内容,所以只要判断文件头不是&&FF FE 和 FE FF 和 EF BB BF就可以认定为 ASCII 编码&&如果对不是记事本保存的 txt 文件,只能用户自己选择用那种编码解码,没有现成的API可以得到某个数据的编码方式。
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 23:13
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
还是这篇文章似乎清楚一些
00:35 GBK的文字编码是双字节来表示的,即不论中、英文字符均使用双字节来表示,只不过为区分中文,将其最高位都定成1。 至于UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8节省空间。 GBK包含全部中文字符; UTF-8则包含全世界所有国家需要用到的字符。 GBK是在国家标准GB2312基础上扩容后兼容GB2312的标准(好像还不是国家标准) UTF-8编码的文字可以在各国各种支持UTF8字符集的浏览器上显示。 比如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,而无需他们下载IE的中文语言支持包。 所以,对于英文比较多的论坛 ,使用GBK则每个字符占用2个字节,而使用UTF-8英文却只占一个字节。 UTF8是国际编码,它的通用性比较好,外国人也可以浏览论坛 GBK是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大~ 对于DZ论坛来说,很多插件都只支持GBK的,如果需要装较多插件的论坛还是用GBK比较好,而对装较少插件且有特殊用户群的论坛用UTF8比较好。 GB2312是GBK的子集,GBK是GB18030的子集 GBK是包括中日韩字符的大字符集合 如果是中文的网站 推荐GB2312 GBK有时还是有点问题 为了避免所有乱码问题,应该采用UTF-8,将来要支持国际化也非常方便 UTF-8可以看作是大字符集,它包含了大部分文字的编码。 使用UTF-8的一个好处是其他地区的用户(如香港台湾)无需安装简体中文支持就能正常观看你的文字而不会出现乱码。 词条:UTF8 UTF8并不算是一种电脑编码,而是一种储存和传送的格式,如前所述,每个Unicode/UCS字符都以 2或4个bytes来储存,看看以下的比较: 以&I am Chinese&为例 用ANSI储存:12 Bytes 用Unicode/UCS2储存:24 Bytes + 2 Bytes(header) 用UCS4储存:48 Bytes + 4 Bytes(header) 以&我是中国人&为例 用ANSI储存:10 Bytes 用Unicode/UCS2储存:10 Bytes + 2 Bytes(header) 用UCS4储存:20 Bytes + 4 Bytes(header) 由此可见直接以Unicode/UCS的原始形式来储存是一种极大的浪费,而且也不利于互联网的传输(中文稍为合算一点^_^)。 有见及此,Unicode/UCS的压缩形式--UTF8出现了,套用官方网站的首句话『UTF-8 stands for Unicode Transformation Format-8. It is an octet (8-bit) lossless encoding of Unicode characters.』,由于UTF也适用于编码UCS,故亦可称为『UCS transformation formats (UTF)』 UTF8是以8bits即1Bytes为编码的最基本单位,当然也可以有基于16bits和32bits的形式,分别称为UTF16和UTF32,但目前用得不多,而UTF8则被广泛应用在文件储存和网络传输中。 编码原理 先看这个模板: UCS-4 range (hex.) UTF-8 octet sequence (binary) 00 007F 0xxxxxxx 00 07FF 110xxxxx 10xxxxxx 00 FFFF 1110xxxx 10xxxxxx 10xxxxxx 1F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx FFF FFFF xxxxxx ... 10xxxxxx 编码步骤: 1) 首先确定需要多少个8bits(octets) 2) 按照上述模板填充每个octets的高位bits 3) 把字符的bits填充至x中,字符顺序:低位→高位,UTF8顺序:最后一个octet的最末位x→第一个octet最高位x 4) 解码的原理一样。 实例:(留意每个bit的颜色,粗体字为模板内容) UCS-4 UTF-8 HEX BIN Bytes BIN HEX Bytes
B6 99 3 不知大家看懂了没有,其实不懂也无所谓,反正又不用自己算,程式可以完全代劳。 以UTF8格式储存的文件档首标识为EF BB BF。 效率 从上述编码原理中得出的结论是: 1.每个英文字母、数字所占的空间为1 Byte; 2.泛欧语系、斯拉夫语字母占2 Bytes; 3.汉字占3 Bytes。 由此可见UTF8对英文来说是个非常诱人的方案,但对中文来说则不太合算,无论用ANSI还是 Unicode/UCS2来编码都只用2 Bytes,但用UTF8则需要3 Bytes。 以下是一些统计资料,显示用UTF8来储存文件每个字符所需的平均字节: 1.拉丁语系平均用1.1 Bytes; 2.希腊文、俄文、阿拉伯文和希伯莱文平均用1.7 Bytes; 3.其他大部份文字如中文、日文、韩文、Hindi(北印度语)用约3 Bytes; 4.用超过4 Bytes的都是些非常少用的文字符号。 词条:GB2312 字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。 GB年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。 GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。 2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。 现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。 从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字 符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属 于双字节字符集 (DBCS)。 有的中文Windows的缺省内码还是GBK,可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符,普通人是很难用到的,通常我们还是用GBK指代中文Windows内码。 这里还有一些细节: GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。 在DBCS中,GB内码的存储格式始终是big endian,即高位在前。 GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是 1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位 是什么。 UNICODE,GBK,UTF-8区别 最近迷上改魔兽地图,破解解压修改挺好玩的~ 有个文件头的问题,搞了半天才知原来是utf-8码...总算把这些都搞清楚了. 简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉 字,那三个码值是完全不一样的.如"汉"的uncode值与gbk就是不一样的,假设uncode为a040,gbk为b030,而uft-8码,就是把 那个值表现的形式.utf-8码完全只针对uncode来组织的,如果GBK要转UTF-8必须先转uncode码,再转utf-8就OK了. 详细的就见下面转的这篇文章. 谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词 这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题: 问题一: 使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢? 我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢? 问题二: 最近在网上看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。对于 Unicode(UCS2)、GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不起来UTF-16和UCS2有什么关系。 查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要求读者知道什么是字节,什么是十六进制。 0、big endian和little endian big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前 面?如果将6C写在前面,就是big endian。如果将49写在前面,就是little endian。 “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,一个皇帝送了命,另一个丢了王位。 我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。 1、字符编码、内码,顺带介绍汉字编码 字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。 GB年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。 GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。 从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中, 英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK都属于双字节字符集 (DBCS)。 2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。 从汉字字汇上说,GB18030在GB902个汉字的基础上增加了CJK扩展A的6582个汉字(Unicode码 0xdb5),一共收录了27484个汉字。 CJK就是中日韩的意思。Unicode为了节省码位,将中日韩三国语言中的文字统一编码。GB13000.1就是ISO/IEC 10646-1的中文版,相当于Unicode 1.1。 GB18030的编码采用单字节、双字节和4字节方案。其中单字节、双字节和GBK是完全兼容的。4字节编码的码位就是收录了CJK扩展A的6582个汉 字。 例如:UCS的0x3400在GB18030中的编码应该是8139EF30,UCS的0x3401在GB18030中的编码应该是8139EF31。 微软提供了GB18030的升级包,但这个升级包只是提供了一套支持CJK扩展A的6582个汉字的新字体:新宋体-18030,并不改变内码。Windows 的内码仍然是GBK。 这里还有一些细节: GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。 对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字节,用两个字节表示一个汉字。 这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码单元是word(双字节),word之间的顺序是编码方案指定的,word内部的 字节排列才会受到endian的影响。后面还会介绍UTF-16。 GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是 1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位 是什么。 2、Unicode、UCS和UTF 前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。 Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是&Universal Multiple-Octet Coded Character Set&,简称为UCS。UCS可以看作是&Unicode Character Set&的缩写。 根据维基百科全书()的记载:历史上存在两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开发了ISO 10646项目,Unicode协会开发了Unicode项目。 在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1相同的字库和字码。 目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode 4.1.0。ISO的最新标准是ISO 3。 UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4个ascii数字来传输、保存这个编码;也 可以用utf-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的好处是它与ISO- 8859-1完全兼容。UTF是“UCS Transformation Format”的缩写。 IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的编码方法。我总是记不得IETF 是Internet Engineering Task Force的缩写。但IETF负责维护的RFC是Internet上一切规范的基础。 2.1、内码和code page 目前Windows的内核已经支持Unicode字符集,这样在内核上可以支持全世界所有的语言文字。但是由于现有的大量程序和文档都采用了某种特定语言的编码,例如GBK,Windows不可能不支持现有的编码,而全部改用Unicode。 Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为前面提到的内码。GBK对应的code page是CP936。 微软也为GB18030定义了code page:CP54936。但是由于GB18030有一部分4字节编码,而Windows的代码页只支持单字节和双字节编码,所以这个code page是无法真正使用的。 3、UCS-2、UCS-4、BMP UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏: UCS-2有2^16=65536个码位,UCS-4有2^31=个码位。 UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字 节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。 group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。 将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。 4、UTF编码 UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下: UCS-2编码(16进制) UTF-8 字节流(二进制) 0000 - 007F 0xxxxxxx 0080 - 07FF 110xxxxx 10xxxxxx 0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx 例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是: 001001, 用这个比特流依次代替模板中的x,得到:01,即E6 B1 89。 读者可以用记事本测试一下我们的编码是否正确。需要注意,UltraEdit在打开utf-8编码的文本文件时会自动转换为UTF-16,可能产生混淆。你可以在设置中关掉这个选项。更好的工具是Hex Workshop。 UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于 0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为 UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。 5、UTF的字节序和BOM UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。 例如“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“ 乙”? Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte order Mark。BOM是一个有点小聪明的想法: 在UCS编码中有一个叫做&ZERO WIDTH NO-BREAK SPACE&的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符&ZERO WIDTH NO-BREAK SPACE&。 这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符&ZERO WIDTH NO-BREAK SPACE&又被称作BOM。 UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符&ZERO WIDTH NO-BREAK SPACE&的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。 Windows就是使用BOM来标记文本文件的编码方式的。 6、进一步的参考资料 本文主要参考的资料是 &Short overview of ISO-IEC 10646 and Unicode& ()。 我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看: &Understanding Unicode A general introduction to the Unicode Standard& () &Character set encoding basics Understanding character set encodings and legacy encodings& () 我写过UTF-8、UCS-2、GBK相互转换的软件包,包括使用Windows API和不使用Windows API的版本。以后有时间的话,我会整理一下放到我的个人主页上()。 我是想清楚所有问题后才开始写这篇文章的,原以为一会儿就能写好。没想到考虑措辞和查证细节花费了很长时间,竟然从下午1:30写到9:00。希望有读者能从中受益。 附录1 再说说区位码、GB2312、内码和代码页 有的朋友对文章中这句话还有疑问: “GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。” 我再详细解释一下: “GB2312的原文”是指国家1980年的一个标准《中华人民共和国国家标准 信息交换用汉字编码字符集 基本集 GB 2312-80》。这个标准用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为“位”。所以也称为区位码。1-9区是中文符号,16-55 区是一级汉字,56-87区是二级汉字。现在Windows也还有区位输入法,例如输入1601得到“啊”。(这个区位输入法可以自动识别16进制的 GB2312和10进制的区位码,也就是说输入B0A1同样会得到“啊”。) 内码是指操作系统内部的字符编码。早期操作系统的内码是与语言相关的。现在的Windows在系统内部支持Unicode,然后用代码页适应各种语言,“内码”的概念就比较模糊了。微软一般将缺省代码页指定的编码说成是内码。 内码这个词汇,并没有什么官方的定义,代码页也只是微软这个公司的叫法。作为程序员,我们只要知道它们是什么东西,没有必要过多地考证这些名词。 所谓代码页(code page)就是针对一种语言文字的字符编码。例如GBK的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。 Windows中有缺省代码页的概念,即缺省用什么编码来解释字符。例如Windows的记事本打开了一个文本文件,里面的内容是字节流:BA、BA、D7、D6。Windows应该去怎么解释它呢? 是按照Unicode编码解释、还是按照GBK解释、还是按照BIG5解释,还是按照ISO8859-1去解释?如果按GBK去解释,就会得到“汉字”两 个字。按照其它编码解释,可能找不到对应的字符,也可能找到错误的字符。所谓“错误”是指与文本作者的本意不符,这时就产生了乱码。 答案是Windows按照当前的缺省代码页去解释文本文件里的字节流。缺省代码页可以通过控制面板的区域选项设置。记事本的另存为中有一项ANSI,其实就是按照缺省代码页的编码方法保存。 Windows的内码是Unicode,它在技术上可以同时支持多个代码页。只要文件能说明自己使用什么编码,用户又安装了对应的代码页,Windows就能正确显示,例如在HTML文件中就可以指定charset。 有的HTML文件作者,特别是英文作者,认为世界上所有人都使用英文,在文件中不指定charset。如果他使用了0x80-0xff之间的字符,中文 Windows又按照缺省的GBK去解释,就会出现乱码。这时只要在这个html文件中加上指定charset的语句,例如: &meta http-equiv=&Content-Type& content=&text/ charset=ISO8859-1&& 如果原作者使用的代码页和ISO8859-1兼容,就不会出现乱码了。 再说区位码,啊的区位码是1601,写成16进制是0x10,0x01。这和计算机广泛使用的ASCII编码冲突。为了兼容00-7f的ASCII编码, 我们在区位码的高、低字节上分别加上A0。这样“啊”的编码就成为B0A1。我们将加过两个A0的编码也称为GB2312编码,虽然GB2312的原文根 本没提到这一点。
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 23:18
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
Herong's Tutorial Notes on GB2312 Character SetVersion 3.05Dr. Herong YangCopyright (c) 1997 - 2007 by Dr. Herong Yang. All rights reserved.
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 23:24
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
GB2312收录了6763个汉字GBK收录了21003个汉字GB收录了27533个汉字GB收录了70244个汉字Unicode 5.0收录了70217个汉字目前看来GB收录了最多汉字。GB18030和Unicode都有足够的码位容纳更多的汉字。Windows内核使用Unicode。简体中文Windows的默认内码是GBK。中文Linux系统使用utf-8比较常见。utf-8是Unicode的一种形式。目前最多人用的汉字编码应该是GBK。如果你想进一步了解Unicode、GB2312、GBK和GB18030中的汉字,可以参考:如果你想进一步了解GB18030,可以参考:如果你想进一步了解文本编码和Unicode,可以参考:
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 00:42
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
Unicode、GB2312、GBK和GB18030中的汉字
Unicode、GB2312、GBK和GB18030中的汉字GB18030有两个版本:GB和GB。GB是GBK的取代版本,它的主要特点是在GBK基础上增加了CJK统一汉字扩充A的汉字。GB的主要特点是在GB基础上增加了CJK统一汉字扩充B的汉字。本文数一数GB18030中的汉字,也顺便看看其它标准中的汉字。 1 Unicode中的汉字在Unicode 5.0的99089个字符中,有71226个字符与汉字有关。它们的分布如下:Block名称 开始码位 结束码位 字符数 CJK统一汉字 4E00 9FBB 20924&&CJK统一汉字扩充A
6582&&CJK统一汉字扩充B D6 42711&&CJK兼容汉字 F900 FA2D 302&&CJK兼容汉字 FA30 FA6A 59&&CJK兼容汉字 FA70 FAD9 106 CJK兼容汉字补充 2F800 2FA1D 542 如果不算兼容汉字,Unicode目前支持的汉字总数是+。这里有一个细节。在早期的Unicode版本中,CJK统一汉字区的范围是0x4E00-0x9FA5,也就是我们经常提到的20902个汉字。当前版本的Unicode增加了22个字符,码位是0x9FA6-0x9FBB。它们是:那么GB18030是否支持这22个字符?后面还会讨论。2 GB23121980年的GB2312一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。这6763个汉字在Unicode中不是连续的,分布在CJK统一汉字字符区(0x4E00-0x9FA5)的20902个汉字中。3 GBK1995年的汉字扩展规范GBK1.0收录了21886个符号,包括21003个汉字和883个其它符号。这21003汉字包括CJK统一汉字区的20902个汉字。余下的101个汉字包括:增补汉字和部首80个,包括28个部首和52个汉字。GBK编码是从FE50-FE7E,FE80-FEA0。下图标注了Unicode编码。
'700')this.width='700';if(this.height>'700')this.height='700';" title="Click Here To EnLarge"> 在制定GBK时,Unicode中还没有这些字符,所以使用了专用区的码位,这80个字符的码位是0xE815-0xE864。后来,Unicode将52个汉字收录到“CJK统一汉字扩充A”。28个部首中有14个部首被收录到“CJK部首补充区”。所以在上图中,这些字符都有两个Unicode编码。上图中淡黄色背景的8个部首被收录到“CJK统一汉字区”的新增区域,即前面提到的0x9FA6-0x9FBB。还有6个淡灰色背景的部首被Unicode收录到“CJK统一汉字扩充B”(网友slt指正)。请注意,淡黄色和淡灰色的14个字符按照GB18030还是应该映射到PUA码位。这14个字符与非PUA码位的映射关系只是网友找出来的,不是标准规定的。如果按照GBK编码,这80个字符应该全部映射到PUA码位。GB18030将其中66个字符映射到了非PUA码位。不过在Windows中,简体中文区域的默认代码页还是GBK,不是GB18030。CJK兼容汉字区挑选出来的21个汉字。见下表: 汉字 GBK编码 Unicode编码 郎 FD9C F92C 凉 FD9D F979 秊 FD9E F995 裏 FD9F F9E7 隣 FDA0 F9F1 兀 FE40 FA0C 嗀 FE41 FA0D 﨎 FE42 FA0E 﨏 FE43 FA0F 﨑 FE44 FA11 﨓 FE45 FA13 﨔 FE46 FA14 礼 FE47 FA18 﨟 FE48 FA1F 蘒 FE49 FA20 﨡 FE4A FA21 﨣 FE4B FA23 﨤 FE4C FA24 﨧 FE4D FA27 﨨 FE4E FA28 﨩 FE4F FA29 4 GB4.1 字汇GB的字汇部分是这样写的:本标准收录的字符分别以单字节、双字节和四字节编码。5.1 单字节部分  本标准中,单字节的部分收录了GB 1到0x7F全部128个字符及单字节编码的欧元符号。5.2 双字节部分  本标准中,双字节的部分收录内容如下:  GB 13000.1的全部CJK统一汉字字符。  GB 13000.1的CJK兼容区挑选出来的21个汉字。  GB 13000.1中收录而GB 2312未收录的我国台湾地区使用的图形字符139个。  GB 13000.1收录的其它字符31个。  GB 2312中的非汉字符号。  GB 12345 的竖排标点符号19个。  GB 2312未收录的10个小写罗马数字。  GB 2312未收录的带音调的汉语拼音字母5个以及ɑ 和ɡ 。  汉字数字“〇”。   表意文字描述符13个。  增补汉字和部首/构件80个。  双字节编码的欧元符号。5.3 四字节部分  本标准的四字节的部分,收录了上述双字节字符之外的,包括CJK统一汉字扩充A在内的GB 13000.1 中的全部字符。4.2 汉字如下表所示,GB收录了27533个汉字:类别&&码位范围&&码位数&&字符数&&字符类型&&双字节部分&&第一字节 0xB0-0xF7第二字节 0xA1-0xFE&&&&汉字&&第一字节0x81-0xA0第二字节0x40-0xFE&&&&汉字&&第一字节0xAA-0xFE第二字节0x40-0xA0&&&&汉字&&四字节部分&&第一字节0x81-0x82第二字节0x30-0x39第三字节0x81-0xFE第四字节0x30-0x39&&&&CJK统一汉字扩充A&&27533就是60+6530。双字节部分的60=21003个汉字就是GBK的21003个汉字。在Unicode中,CJK统一汉字扩充A有6582个汉字,为什么这里只有6530个汉字?这是因为在GBK时代,双字节部分已经收录过CJK统一汉字扩充A的52个汉字,所以还余6530个汉字。5 GB5.1 字汇GB的字汇部分是这样写的:本标准收录的字符分别以单字节、双字节或四字节编码。5.1 单字节部分  本标准中,单字节的部分收录了GB/T 的0x00到0x7F全部128个字符。5.2 双字节部分  本标准中,双字节的部分收录内容如下:  GB 93的全部CJK统一汉字字符。见附录A。  GB 93的CJK兼容区挑选出来的21个汉字。见附录A。  GB 93中收录而GB 2312未收录的我国台湾地区使用的图形字符139个。见附录A。  GB 93收录的其它字符31个。见附录A。  GB 2312中的非汉字符号。见附录A。  GB 12345 的竖排标点符号19个。见附录A。  GB 2312未收录的10个小写罗马数字。见附录A。  GB 2312未收录的带音调的汉语拼音字母5个以及ɑ 和ɡ 。见附录A。  汉字数字“〇”。 见附录A。  表意文字描述符13个。见附录A和附录B。  对GB 93增补的汉字和部首/构件80个。见附录A和附录C。  双字节编码的欧元符号。见附录A。5.3 四字节部分  本标准的四字节的部分,收录了上述双字节字符之外的,GB 13000的CJK统一汉字扩充A、CJK统一汉字扩充B和已经在GB13000中编码的我国少数民族文字的字符。见附录D。GB最主要的变化是增加了CJK统一汉字扩充B。它还去掉了单字节编码的欧元符号(0x80)。5.2 汉字如下表所示,GB收录了70244个汉字:类别&&码位范围&&码位数&&字符数&&字符类型&&双字节部分&&第一字节 0xB0-0xF7第二字节 0xA1-0xFE&&&&汉字&&第一字节0x81-0xA0第二字节0x40-0xFE&&&&汉字&&第一字节0xAA-0xFE第二字节0x40-0xA0&&&&汉字&&四字节部分&&第一字节0x81-0x82第二字节0x30-0x39第三字节0x81-0xFE第四字节0x30-0x39&&&&CJK统一汉字扩充A&&第一字节0x95-0x98第二字节0x30-0x39第三字节0x81-0xFE第四字节0x30-0x39&&4&&CJK统一汉字扩充B&&70244就是60+。6 结束语GB个汉字,GBK有21003个汉字,GB有27533个汉字,GB有70244个汉字。Unicode 5.0中,如果不算兼容区,目前有70217个汉字。让我们比较一下Unicode的70217汉字和GB中的70244汉字:GB Unicode 5.0 对应的Unicode编码 CJK统一汉字的20902汉字 CJK统一汉字的20902汉字 0x4E00-0x9FA5 CJK统一汉字扩充A的6582汉字 CJK统一汉字扩充A的6582汉字 0xDB5 CJK统一汉字扩充B的42711汉字 CJK统一汉字扩充B的42711汉字 0xA6D6 CJK部首补充区的14个部首 未计入 2E81, 2E84, 2E88, 2E8B, 2E8C, 2E97, 2EA7, 2EAA, 2EAE, 2EB3, 2EB6, 2EB7, 2EBB, 2ECA CJK兼容汉字区的21个汉字 未计入 F92C, F979, F995, F9E7, F9F1, FA0C, FA0D, FA0E, FA0F, FA11, FA13, FA14, FA18, FA1F, FA20, FA21, FA23, FA24, FA27, FA28, FA29
CJK统一汉字区新增了这8个字符 0x9FB4-0x9FBB 未计入 CJK统一汉字区新增的14个字符 0x9FA6-0x9FB3 因为GB18030映射了Unicode的所有码位,所以CJK统一汉字区新增的0x9FA6-0x9FB3这14个字符在GB18030中都有对应的码位。不过GB18030没有明确收录这些字符。附录1 GB18030的汉字编码表我整理了GB18030的汉字编码表,需要的朋友可以下载。以下是其中的简要说明:简要说明将表1(21003)和表2(6530)合起来就是GB要求的27533个汉字将表1(21003)、表2(6530)和表3(42711)合起来就是GB要求的70244个汉字Unicode的扩充A本来有6582个汉字,因为GB18030的双字节区已经收录过Unicode扩充A的52个汉字,所以GB18030四字节区扩充A只有6530个汉字。表4列出了这52个汉字。GBK增补的80个字符本来是放在PUA区的。后来又被Unicode收录。所以既可以用PUA区的编码表示,也可以用非PUA编码表示。如下表所示。&&发表于 @ 日 20:58:00 本文来自CSDN博客,转载请标明出处:
(964 K) 下载次数:246
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 00:51
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
GB18030编码研究以及GBK、GB18030与Unicode的映射
GB18030编码研究以及GBK、GB18030与Unicode的映射GB18030有两个版本:GB和GB。在本文中,没有指明版本的GB18030是指GB。本文讨论了以下问题:GB个图形符号,都放在1区。GBK的1区有717个图形符号,5区有166个图形符号,一共有883个图形符号。GB18030的1区有728个图形符号,5区还是166个符号。那么,GBK的1区在GB2312基础上增加了哪35个符号?GB18030又增加了哪些符号? GBK支持21003个汉字与883个图形符号,一共21886个字符。这21886个字符究竟是哪些字符?这21886个字符的编码在GB18030中有什么变化? GB18030是怎样映射Unicode的全部0x110000个码位的? GB和GB在字汇上有什么区别,在编码上有什么区别? GB的双字节区中有2067个码位被映射到Unicode BMP的PUA。这些码位有什么规律?这些码位中定义了多少字符?其实这2067个码位中只定义了24个字符。 GBK的21886个字符中有95个字符被映射到Unicode BMP的PUA。在GB18030中这95个字符的编码有哪些变化?哪些字符保持了原来的编码? GBK的23940个码位中有多少码位被映射到Unicode BMP的PUA?在GB18030中这些码位的编码有什么变化? 在讨论这些问题前,我们先约定一下码位空间的表示方法。0 码位空间0.1 约定GBK是双字节编码,每个字符用两个字节表示。GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。码位空间由各字节的范围确定。例如:GB18030的四字节字符码位空间是:第一字节在0x81~0xFE之间 第二字节在0x30~0x39之间 第三字节在0x81~0xFE之间 第四字节在0x30~0x39之间 为了表述方便,我们用0xxFE39FE39表示这个码位空间。也就是说:在本文中0xxFE39FE39所指的并不是从0xxFE39FE39的连续(0xFE39FE39-0x)个字节。在本文中,0xxFE39FE39所指的是编码的各字节在对应范围内的码位空间,这个码位空间的码位数目是:(0xFE-0x81+1)*(0x39-0x30+1)*(0xFE-0x81+1)*(0x39-0x30+1)=126*10*126*10=1587600同理,0xB0A1~0xF7FE代表的码位空间是第一字节在0xB0~0xF7之间,第二字节在0xA1~0xFE之间的所有码位。这个码位空间的码位数目是:(0xF7-0xB0+1)*(0xFE-0xA1+1)=72*94=6768这个码位空间就是GBK和GB18030的2区,在这6768个码位中定义了6763个字符。本文用~表示上述码位空间,用-表示一般的范围,即:0xA1A1~0xA9FE 表示第一字节在0xA1到0xA9之间,第二字节在0xA1~0xFE之间的846((0xA9-0xA1+1)*(0xFE-0xA1+1)=9*94)个码位。 0xE000-0xF8FF 表示从0xE000-0xF8FF的连续FF-0xE000+1)个码位。 0.2 习题读者如果已经理解了上面的约定,请完成下面两个习题:习题一:求码位空间0x8140~0xFE7E的码位数目。 习题二:求码位空间0x8180~0xFEFE的码位数目。 0.3 答案以下是习题0.2的答案:习题一:(0xFE-0x81+1)*(0x7E-0x40+1)=126*63=7938 习题二:(0xFE-0x81+1)*(0xFE-0x80+1)=126*127=16002 GB18030双字节字符的码位空间就是0x8140~0xFE7E和0x8180~0xFEFE,双字节字符的码位数目是=20~0xFE7E和0x8180~0xFEFE也是GBK的全部码位空间。GBK在这23940个码位中定义了21886个字符。1 GBK回顾1.1 简介GBK是双字节编码方案。它的码位空间就是前面所说的0x8140~0xFE7E和0x8180~0xFEFE,一共23940个码位。在这23940个码位上定义了21886个字符,包括21003个汉字和883个图形符号。《Unicode、GB2312、GBK和GB18030中的汉字》详细讨论了这21003个汉字。本文的第3节会讨论GB2312、GBK和GB18030的图形符号。GBK的码位空间可以划分为以下区域:类别 区名 码位范围 码位数 字符数 符号区 1区 0xA1A1~0xA9FE 846 717 5区 0xA840~0xA97E和0xA880~0xA9A0 192 166 汉字区 2区 0xB0A1~0xF7FE
3区 0xE和0xFE
4区 0xAA40~0xFE7E和0xAA80~0xFEA0
用户自定义区 用户区1 0xAAA1~0xAFFE 564&&用户区2 0xF8A1~0xFEFE 658&&用户区3 0xA140~0xA77E和0xA180~0xA7A0 672&&1.2 GBK字符与Unicode的映射我制作了一个Excel文件:附件1。这个文件包含3张表格:按照GBK编码排序的GBK全部21886字符码表。这个表格有3列:字符、GBK编码、Unicode编码。 按照Unicode编码排序的GBK全部21886字符码表。这个表格有3列:字符、Unicode编码、GBK编码。 从按Unicode编码排序的表格中,很容易找到被映射到PUA(0xE000-0xF8FF)的字符。GBK的21886个字符中有95个字符属于PUA。第三张表格列出了这95个字符(A列)的GBK编码(B列)、Unicode编码(C列)以及这些字符在GB18030中对应的Unicode编码(D列)。其中D列可能不太容易理解,我再解释一下。GB18030是兼容GBK的,所以这些字符的GBK编码和GB18030编码是相同的。例如的GBK编码和GB18030编码都是0xA8BF。但是在GBK和GB18030中,被映射到不同的Unicode码位。在GBK中,0xA8BF被映射到Unicode的0xE7C8。在Unicode中,码位0xE7C8是一个PUA码位,保留给用户使用。在GB18030中,0xA8BF被映射到Unicode的0x01F9。在Unicode中,码位0x01F9属于“拉丁字母扩充-B”这个Block,这个码位定义的字符是“带抑音符的拉丁文小写字母 N”,字形就是。 1.3 GBK码位与Unicode的映射GBK的23940个码位定义了21886个字符,还有=2054个空闲码位,这2054个码位都被映射到Unicode的PUA。在设计GBK时,GBK的21886个字符中有95个在Unicode中没有对应字符,所以这95个字符也被映射到Unicode的PUA。在GBK的23940个码位中,一共有9个码位被映射到PUA,对应的PUA编码是0xE000-0xE864。0xE000-0xE864就是2149个码位。这2149个码位的分配有以下规律:码位所在区域 码位数量 映射到的PUA范围 用户区1:0xAAA1~0xAFFE 564 0xE000-0xE233 用户区2:0xF8A1~0xFEFE 658 0xE234-0xE4C5 用户区3:0xA140~0xA77E和A180-A7A0 672 0xE4C6-0xE765 符号区(1区和5区)的170个空闲码位 170 0xE766-0xE80F 2区的5个空闲码位:0xD7FA-0xD7FE 5 0xE810-0xE814 4区的80个Unicode当时没有定义的字符:FE50-FE7E和FE80-FEA0 80 0xE815-0xE864 附件2包含两张表格:23940个GBK码位与Unicode的映射。两组数据分别按GBK和Unicode排序。 2149个映射到PUA的码位,按Unicode顺序排列。 2 GB18030编码2.1 概述GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。GB18030的码位定义如下:字节数 码位空间 码位数 字符数 单字节 0x00~0x7F 128 128 双字节 0x8140~0xFE7E和0x8180~0xFEFE
四字节 0xxFE39FE39 31 GB1940+1668个码位。Unicode的码位数目是0x14112),少于GB18030。所以,GB18030有足够的空间映射Unicode的所有码位。GB18个码位目前定义了128+=76556个字符。Unicode 5.0定义了99089个字符。2.2 设计思路GB18030编码可以分为:单字节部分、双字节部分和四字节部分。单字节部分与Unicode的0x00-0x7f完全相同。双字节部分与GBK有两点差异:在1区增加了11个字符。这样1区就有717+11=728个字符。增加的11个字符是:一个欧元符号(0xA2E3)和10个竖排标点符号(0xA6D9-0xA6DF、0xA6EC-0xA6ED和0xA6F3)。 原来因为Unicode没有收录而映射到PUA的字符中的部分字符被新版本的Unicode收录,所以将这些字符映射到非PUA的码位。 Unicode的BMP一共有65536个码位。其中代理区(0xD800-0xDFFF)有2048个码位,这2048个码位是不能定义字符的。GB18030的单字节部分映射了128个码位,GB18030的双字节部分映射了23940个码位。还剩下-128-个码位。GB18030将这39420个码位顺序映射到从0x开始的码位空间。GB18030将Unicode的16个辅助平面(0xFFFF,一共1048576个码位)顺序映射到从0x开始的码位空间。GB18030四字节部分中只有这两个区域定义了字符,其它空间都是保留区和自定义区。本文的第3节和第4节还会详细讨论GB18030的双字节和四字节部分。GB18030的设计思路可以概括到以下几点:单字节部分与Unicode一致。 双字节部分与GBK兼容。适当调整一些字符与Unicode的映射。这些字符原来因为Unicode没有收录而被映射到PUA,现在因为Unicode已经收录而调整到非PUA的Unicode码位。 将Unicode BMP部分还没有映射的39420个码位顺序映射到从0x开始的四字节部分。 将Unicode BMP以外的16个辅助平面映射到39420个码位顺序映射到从0x开始的四字节部分。 在GB18030目前定义的76556个字符中,只有24个字符被定义到Unicode的PUA区。这24个字符包括1区的10个竖排标点符号(0xA6D9-0xA6DF、0xA6EC-0xA6ED和0xA6F3)和4区的14个汉字(0xFE51、0xFE52、0xFE53、0xFE59、0xFE61、0xFE66、0xFE67、0xFE6C、0xFE6D、0xFE76、0xFE7E、0xFE90、0xFE91、0xFEA0)。4区的14个汉字在Unicode 5.0中其实也可以找到非PUA的编码,详见《Unicode、GB2312、GBK和GB18030中的汉字》。但按照GB18030,它们还是应该映射到PUA码位。2.3 GB和GB的区别及以后版本GB与GB的编码体系结构是完全相同的。GB相对于GB主要有以下变化:在四字节字符表中增加CJK统一汉字扩充B和已经在GB13000中编码的我国少数民族文字字符的字形。其实GB已经映射了这些码位,但GB没有给出这些字符的字形。 调整字符的编码。 其中的编码调整比较有意思。的GB18030编码是0xA8BC,在Unicode 5.0的编码是0x1E3F。在GB中0xA8BC被映射到Unicode的0xE7C7,因为双字节部分没有映射0x1E3F,所以它作为BMP的未映射字符被放到四字节部分的0x。GB将0xA8BC映射到0x1E3F,那么Unicode码位0xE7C7怎么办呢?为了最小化对原来编码的影响,设计者将Unicode码位0xE7C7映射到本来映射0x1E3F的0x。GB18030已经映射了Unicode的所有码位,所以不管Unicode怎么变化,GB18030不过就是在现在的码位上增加一些字形而已,编码不会变化。只有现在还映射到PUA的24个字符以后可能会调整到非PUA码位。调整方法应该与的调整方法相同。2.4 GB18030双字节部分前面已经介绍过GB18030双字节部分与GBK的区别,本小节再提一些细节。前面也说过,GB18030映射了Unicode除代理区外的所有码位。所以,Unicode BMP的6400个PUA码位在GB18030中都有对应的码位。GB18030双字节部分映射了2067个PUA码位。前面说过,GBK映射了2149个PUA码位。现在GB18030双字节部分映射了2067个PUA码位。所以有个字符的映射发生了变化。GBK原来有95个字符映射到PUA,其中81个字符在GB18030中被映射到非PUA码位。余下的14个汉字就是《Unicode、GB2312、GBK和GB18030中的汉字》提到的那14个汉字(0xFE51、0xFE52、0xFE53、0xFE59、0xFE61、0xFE66、0xFE67、0xFE6C、0xFE6D、0xFE76、0xFE7E、0xFE90、0xFE91、0xFEA0)。附件1列出了这些字符的编码变化。82个映射变化的码位,除了这81个外,还有一个就是欧元符号:GB18030编码是0xA2E3,Unicode编码是0x20AC。码位0xA2E3在GBK中被映射到0xE76C,GBK的码位0xA2E3没有定义字符。GB18030双字节部分与Unicode的映射没有规律,只能通过查表方法映射。2.5 GB18030四字节部分GB18030四字节部分的字符可以见GB的“表3 四字节部分的码位安排”,一共54531个字符。GB18030四字节部分的码位可以见GB的“7.3 四字节部分字符的排列顺序”。其中定义字符的只有两个区域:GB18030用码位0xx400个码位映射该标准单字节和双字节部分没有映射过的39420个Unicode BMP码位。 GB18030用码位0xxE339FE39共1058400个码位映射Unicode 16个辅助平面(平面1到平面16)的8576个码位。 为了叙述方便,本文将0xx8439FE39称作“BMP扩展部分”,将0xxE339FE39称作“辅助平面部分”。GB18030四字节部分的码位空间是0xxFE39FE39。第二字节有(0x39-0x30+1)=10个可能值。第三字节有(0xFE-0x81+1)=126个可能值。第四字节也是(0x39-0x30+1)=10个可能值。为了方便下面的演算,本文为这个码位空间定义几个名词:我们将四字节码位空间中第一字节相同的区域称作一级区。每个一级区有12600个码位,即:10*126*10。 我们将四字节码位空间中第一字节和第二字节相同的区域称作二级区。每个二级区有1260个码位,即:126*10。 我们将四字节码位空间中前三个字节相同的区域称作三级区,每个三级区有10个码位。 四字节部分一共有(0xFE-0x81+1)=126个一级区。BMP扩展部分有4个一级区。辅助平面部分有84个一级区。还有38个一级区是保留区或自定义区。2.5.1 BMP扩展部分BMP扩展部分占据四字节部分开头的4个一级区,一共有4*个码位。这段空间的Unicode映射说起来还是很简单的,就是顺序映射单字节、双字节没有映射过的BMP码位。这些映射关系在GB中确定下来。以后的调整(例如)只是个别字符,不会影响其它字符的位置。但是因为双字节字符已经映射过的BMP码位没有什么规律,所以造成BMP扩展部分的Unicode映射也不能用公式换算,还是要查表解决。显然这50400个码位中只用到了39420个码位,其余码位都是保留的。出于好玩,我们来计算一下最后一个非保留码位(0xFFFF)的位置,计算过程如下:m1=(600=3 n1=(600=1619 m2=n1/60=1 n2=n1%60=359 m3=n2/10=359/10=35 n3=n2%10=359%10=9 第一字节的位置是:0x81+m1=0x81+3=0x84 第二字节的位置是:0x30+m2=0x30+1=0x31 第三字节的位置是:0x81+m3=0x81+35=0xA4 第四字节的位置是:0x30+n3=0x30+9=0x39 所以Unicode编码0xFFFF映射的GB18030码位是0x。在BMP扩展部分中,0x以后的码位都是保留码位。上述计算中,/表示整除(例如5/3=1),%表示取余(例如5%3=2)。 2.5.2 辅助平面部分辅助平面部分用84个一级区(0xxE339FE39)直接映射Unicode的16个辅助平面。这部分映射是可以直接用公式计算的。让我们看看怎么计算。从Unicode编码到GB18030编码的映射方法如下:U=Unicode编码-0x10000 m1=U/12600 n1=U%12600 m2=n1/1260 n2=n1%1260 m3=n2/10 n3=n2%10 第一字节b1=m1+0x90 第二字节b2=m2+0x30 第三字节b3=m3+0x81 第四字节b4=n3+0x30 按照上述方法可以计算出0x10FFFF被映射到0xE3329A35。在辅助平面部分,0xE3329A35以后的码位都是保留码位。以上所写的算法可以很容易写成C/C++代码。对于不会编程的读者,也可以用Excel公式计算。假设Unicode编码放在单元格A12,计算方法如下:将m1放在B12,B12=INT((HEX2DEC(A12)-6) 将n1放在C12,C12=MOD((HEX2DEC(A12)-6) 将m2放在D12,D12=INT(C12/1260) 将n2放在E12,E12=MOD(C12,1260) 将m3放在F12,F12=INT(E12/10) 将n3放在G12,G12=MOD(E12,10) 将第一字节放在H12,H12=DEC2HEX(B12+144) 将第二字节放在I12,I12=DEC2HEX(D12+48) 将第三字节放在J12,J12=DEC2HEX(F12+129) 将第四字节放在K12,K12=DEC2HEX(G12+48) 附件3中有写好上述公式的Excel表格。使用函数HEX2DEC/DEC2HEX需要通过“工具-&加载宏”钩上“分析工具库”。 从GB18030编码到Unicode编码的映射方法如下: 设GB18030编码的四个字节依次为:b1、b2、b3、b4,则Unicode编码=0x10000+(b1-0x90)*12600+(b2-0x30)*1260+(b3-0x81)*10+b4-0x30 假设b1、b2、b3、b4分别放在A4、B4、C4、D4,Unicode编码放在E4,则Excel计算公式为: E4 = =DEC2HEX((HEX2DEC(A4)-144)*12600+(HEX2DEC(B4)-48)*1260+(HEX2DEC(C4)-129)*10+(HEX2DEC(D4)-48)+65536) 2.6 GB18030和Unicode的映射表附件3给出了GB18030和Unicode的映射表。这个Excel文件是在网友谢振斌先生的映射表基础上制作的,包含3张表格:双字节部分23940个码位与Unicode的映射。两组数据分别按GB18030和Unicode排序。 BMP扩展部分39420个码位与Unicode的映射。两组数据分别按GB18030和Unicode排序。 辅助平面部分,GB18030编码和Unicode编码的映射公式。 3 GB2312、GBK和GB18030中的图形符号在研究GB18030编码的过程中,我整理了GB2312、GBK和GB18030在1区和5区的图形符号,制作了附件4。这个Excel文件包含3张表格:GB2312的1区字符表。GBK和GB18030的1区、5区字符表。用不同颜色标注了GBK增加的35个字符和GB18030增加的11个字符。 GB2个符号的编码。 GBK 1区717个符号的编码。 结束语通过本文的介绍,读者可以回答开头的问题了吗?无论是Windows XP还是Vista,中文(中国)区域对应的默认代码页还是GBK。我们只能设置区域,并不能设置区域对应的默认代码页。所以在Windows世界,只要微软不愿意,GB18030就只是一张普通的代码页。目前的简体中文文档使用的编码主要是Unicode和GBK,应该没有什么文档会用GB18030保存。本文只是出于程序员的好奇而对GB18030编码所作的一些研究,希望能对同样好奇的读者有所助益。本文来自CSDN博客,转载请标明出处:
(1180 K) 下载次数:430
(842 K) 下载次数:1287
(617 K) 下载次数:272
(23 K) 下载次数:390
殆知阁藏书子站可以在线阅读以及全文检索本站现有的全部古代文献资料。请大家都帮忙测试一下。http://wenxian.fanren8.com/&&谢谢。。
发表于: 00:56
无边虚空,觉所显发。觉圆明故,显心清静。心清静故,四大六根十二处十八界二十五有,皆得清静。
级别: 总纂
发帖: 30219
威望: 58984 点
金钱: 0 RMB
所在城市:beij
在线时间:4919(小时)
浅谈文字编码和Unicode
浅谈文字编码和Unicode我曾经写过一篇《谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词》(以下简称《谈谈Unicode编码》),在网上流传较广,我也收到不少朋友的反馈。本文探讨《谈谈Unicode编码》中未介绍或介绍较少的代码页、Surrogates等问题,补充一些Unicode资料,顺带介绍一下我最近编写的一个Unicode工具:UniToy。本文虽然是前文的补充,但在写作上尽量做到独立成篇。标题中的“浅谈”是对自己的要求,我希望文字能尽量浅显易懂。但本文还是假设读者知道字节、16进制,了解《谈谈Unicode编码》中介绍过的字节序和Unicode的基本概念。0 UniToyUniToy是我编写的一个小工具。通过UniToy,我们可以全方位、多角度地查看Unicode,了解Unicode和语言、代码页的关系,完成一些文字编码的相关工作。本文的一些内容是通过UniToy演示的。大家可以从我的网站()下载UniToy的演示版本。 1 文字的显示1.1 发生了什么?我们首先以Windows为例来看看文字显示过程中发生了什么。用记事本打开一个文本文件,可以看到文件包含的文字:如果我们用UltraEdit或Hex Workshop查看这个文件的16进制数据,可以看到:我们看到:文件“例子GBK.txt”有10个字节,依次是“D7 D6 B7 FB BA CD B1 E0 C2 EB”,这就是记事本从文件中读到的内容。记事本是用来打开文本文件的,所以它会调用Windows的文本显示函数将读到的数据作为文本显示。Windows首先将文本数据转换到它内部使用的编码格式:Unicode,然后按照文本的Unicode去字体文件中查找字体图像,最后将图像显示到窗口上。总结一下前面的分析,文字的显示应该是这样的: 步骤1:文字首先以某种编码保存在文件中。 步骤2:Windows将文件中的文字编码映射到Unicode。 步骤3:Windows按照Unicode在字体文件中查找字体图像,画到窗口上。 所谓编码就是用数字表示字符,例如用D7D6表示“字”。当然,编码还意味着约定,即大家都认可。从《谈谈Unicode编码》中,我们知道Unicode也是一种文字编码,它的特殊性在于它是由国际组织设计,可以容纳全世界所有语言文字。而我们平常使用的文字编码通常是针对一个区域的语言、文字设计,只支持特定的语言文字。例如:在上面的例子中,文件“例子GBK.txt”采用的就是GBK编码。 如果上述3个步骤中任何一步发生了错误,文字就不能被正确显示,例如: 错误1:如果弄错了编码,例如将Big5编码的文字当作GBK编码,就会出现乱码。错误2:如果从特定编码到Unicode的映射发生错误,例如文本数据中出现该编码方案未定义的字符,Windows就会使用缺省字符,通常是?。如果当前字体不支持要显示的字符,Windows就会显示字体文件中的缺省图像:空白或方格。 在Unicode被广泛使用前,有多少种语言、文字,就可能有多少种文字编码方案。一种文字也可能有多种编码方案。那么我们怎么确定文本数据采用了什么编码? 1.2 采用了哪种编码?按照惯例,文本文件中的数据都是文本编码,那么它怎么表明自己的编码格式?在记事本的“打开”对话框上:我们可以看到记事本支持4种编码格式:ANSI、Unicode、Unicode big endian、UTF-8。如果读者看过《谈谈Unicode编码》,对Unicode、Unicode big endian、UTF-8应该不会陌生,其实它们更准确的名称应该是UTF-16LE(Little Endian)、UTF-16BE(Big Endian)和UTF-8,它们是基于Unicode的不同编码方案。 在《谈谈Unicode编码》中介绍过,Windows通过在文本文件开头增加一些特殊字节(BOM)来区分上述3种编码,并将没有BOM的文本数据按照ANSI代码页处理。那么什么是代码页,什么是ANSI代码页? 2 代码页和字符集2.1 Windows的代码页2.1.1 代码页代码页(Code Page)是个古老的专业术语,据说是IBM公司首先使用的。代码页和字符集的含义基本相同,代码页规定了适用于特定地区的字符集合,和这些字符的编码。可以将代码页理解为字符和字节数据的映射表。Windows为自己支持的代码页都编了一个号码。例如代码页936就是简体中文 GBK,代码页950就是繁体中文 Big5。代码页的概念比较简单,就是一个字符编码方案。但要说清楚Windows的ANSI代码页,就要从Windows的区域(Locale)说起了。 2.1.2 区域和ANSI代码页微软为了适应世界上不同地区用户的文化背景和生活习惯,在Windows中设计了区域(Locale)设置的功能。Local是指特定于某个国家或地区的一组设定,包括代码页,数字、货币、时间和日期的格式等。在Windows内部,其实有两个Locale设置:系统Locale和用户Locale。系统Locale决定代码页,用户Locale决定数字、货币、时间和日期的格式。我们可以在控制面板的“区域和语言选项”中设置系统Locale和用户Locale:每个Locale都有一个对应的代码页。Locale和代码页的对应关系,大家可以参阅我的另一篇文章《谈谈Windows程序中的字符编码》的附录1。系统Locale对应的代码页被作为Windows的默认代码页。在没有文本编码信息时,Windows按照默认代码页的编码方案解释文本数据。这个默认代码页通常被称作ANSI代码页(ACP)。ANSI代码页还有一层意思,就是微软自己定义的代码页。在历史上,IBM的个人计算机和微软公司的操作系统曾经是PC的标准配置。微软公司将IBM公司定义的代码页称作OEM代码页,在IBM公司的代码页基础上作了些增补后,作为自己的代码页,并冠以ANSI的字样。我们在“区域和语言选项”高级页面的代码页转换表中看到的包含ANSI字样的代码页都是微软自己定义的代码页。例如:874 (ANSI/OEM - 泰文) 932 (ANSI/OEM - 日文 Shift-JIS) 936 (ANSI/OEM - 简体中文 GBK) 949 (ANSI/OEM - 韩文) 950 (ANSI/OEM - 繁体中文 Big5) 1250 (ANSI - 中欧) 1251 (ANSI - 西里尔文) 1252 (ANSI - 拉丁文 I) 1253 (ANSI - 希腊文) 1254 (ANSI - 土耳其文) 1255 (ANSI - 希伯来文) 1256 (ANSI - 阿拉伯文) 1257 (ANSI - 波罗的海文) 1258 (ANSI/OEM - 越南) 在UniToy中,我们可以按照代码页编码顺序查看这些代码页的字符和编码:
我们不能直接设置ANSI代码页,只能通过选择系统Locale,间接改变当前的ANSI代码页。微软定义的Locale只使用自己定义的代码页。所以,我们虽然可以通过“区域和语言选项”中的代码页转换表安装很多代码页,但只能将微软的代码页作为系统默认代码页。2.1.3 代码页转换表在Windows 2000以后,Windows统一采用UTF-16作为内部字符编码。现在,安装一个代码页就是安装一张代码页转换表。通过代码页转换表,Windows既可以将代码页的编码转换到UTF-16,也可以将UTF-16转换到代码页的编码。代码页转换表的具体实现可以是一个以nls为后缀的数据文件,也可以是一个提供转换函数的动态链接库。有的代码页是不需要安装的。例如:Windows将UTF-7和UTF-8分别作为代码页65000和代码页65001。UTF-7、UTF-8和UTF-16都是基于Unicode的编码方案。它们之间可以通过简单的算法直接转换,不需要安装代码页转换表。在安装过一个代码页后,Windows就知道怎样将该代码页的文本转换到Unicode文本,也知道怎样将Unicode文本转换成该代码页的文本。例如:UniToy有导入和导出功能。所谓导入功能就是将任一代码页的文本文件转换到Unicode文本;导出功能就是将Unicode文本转换到任一指定的代码页。这里所说的代码页就是指系统已安装的代码页:其实,如果全世界人民在计算机刚发明时就统一采用Unicode作为字符编码,那么代码页就没有存在的必要了。可惜在Unicode被发明前,世界各国人民都发明并使用了各种字符编码方案。所以,Windows必须通过代码页支持已经被广泛使用的字符编码。从这种意义看,代码页主要是为了兼容现有的数据、程序和习惯而存在的。2.1.4 SBCS、DBCS和MBCSSBCS、DBCS和MBCS分别是单字节字符集、双字节字符集和多字节字符集的缩写。SBCS、DBCS和MBCS的最大编码长度分别是1字节、两字节和大于两字节(例如4或5字节)。例如:代码页1252 (ANSI-拉丁文 I)是单字节字符集;代码页936 (ANSI/OEM-简体中文 GBK)是双字节字符集;代码页54936 (GB18030 简体中文)是多字节字符集。 单字节字符集中的字符都用一个字节表示。显然,SBCS最多只能容纳256个字符。 双字节字符集的字符用一个或两个字节表示。那么我们从文本数据中读到一个字节时,怎么判断它是单字节字符,还是双字节字符的首字符?答案是通过字节所处范围来判断。例如:在GBK编码中,单字节字符的范围是0x00-0x80,双字节字符首字节的范围是0x81到0xFE。我们顺序读取字节数据,如果读到的字节在0x81到0xFE内,那么这个字节就是双字节字符的首字节。GBK定义双字节字符的尾字节范围是0x40到0x7E和0x80到0xFE。 GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。这时我们又如何判断一个字节是属于单字节字符,双字节字符,还是四字节字符?GB18030与GBK是兼容的,它利用了GBK双字节字符尾字节的未使用码位。GB18030的四字节字符的第一字节的范围也是0x81到0xFE,第二字节的范围是0x30-0x39。通过第二字节所处范围就可以区分双字节字符和四字节字符。GB18030定义四字节字符的第三字节范围是0x81到0xFE,第四字节范围是0x30-0x39。 2.2 代码页实例2.2.1 实例一:GB18030代码页1.1节的“错误2”中演示了一个全被显示成'?'的文件。这个文件的数据是: 其实,这是一个包含了6个四字节字符的GB18030编码的文件。记事本按照GBK显示这些数据,而GB18030的四字节字符编码在GBK中是未定义的。Windows根据首字节范围判断出12个双字节字符,然后因为找不到匹配的转换而将其映射到默认字符'?'。使用UniToy按照GB18030代码页导入这个文件,就可以看到:
这个GB18030编码的文件是用UniToy创建的,编辑Unicode文本,然后导出到GB18030编码格式。 2.2.2 实例二:GBK和Big5的转换综合使用UniToy的导入、导出功能就可以在任意两个代码页之间转换文本。其实,由于各代码页支持的字符范围不同,我们一般不会直接在代码页间转换文本。例如将以下GBK编码的文本:直接转换到Big5编码,就会看到:变成'?'的字符都是Big5编码不支持的简化字。在从Unicode转换到Big5编码时,由于Big5编码不支持这些字符,Windows就用默认字符'?'代替。在UniToy中,我们可以先将简体字转换到繁体字,然后再导出到Big5编码,就可以正常显示:同理,将Big5编码的文本转换到GBK编码的步骤应该是:将Big5编码的文本导入到Unicode文本; 将繁体的Unicode文本转换简体的Unicode文本; 将简体的Unicode文本导出到GBK文本。 2.3 互联网的字符集2.3.1 字符集互联网上的信息缤纷多彩,但文本依然是最重要的信息载体。html文件通过标记表明自己使用的字符集。例如:&meta http-equiv=&Content-Type& content=&text/ charset=utf-8&&或者:&meta http-equiv=&charset& content=&iso-8859-1&&那么我们可以使用哪些字符集(charset)呢?在IETF(互联网工程任务组)的网页上维护着一份可以在互联网上使用的字符集的清单:CHARACTER SETS。如果有新的字符集被登记,IETF会更新这份文档。 简单浏览一下,日的版本列出了253个字符集。其中也包括微软的CP1250 ~ CP1258,在这里它们不会被称作什么ANSI代码页,而是被简单地称作windows-1250、windows-1251等。其实在Unicode被广泛使用前,除了中日韩等大字符集,世界上,特别是西方使用最广泛的字符集应该是ISO 8859系列字符集。2.3.2 ISO 8859系列字符集ISO 8859系列字符集是欧洲计算机制造商协会(ECMA)在上世纪80年代中期设计,并被国际标准化(ISO)组织采纳为国际标准。ISO 8859系列字符集目前有15个字符集,包括:ISO 8859-1 大部分的西欧语系,例如英文、法文、西班牙文和德文等(Latin-1) ISO 8859-2 大部分的中欧和东欧语系,例如捷克文、波兰文和匈牙利文等(Latin-2) ISO 8859-3 欧洲东南部和其它各种文字(Latin-3) ISO 8859-4 斯堪的那维亚和波罗的海语系(Latin-4) ISO 8859-5 拉丁文与斯拉夫文(俄文、保加利亚文等) ISO 8859-6 拉丁文与阿拉伯文 ISO 8859-7 拉丁文与希腊文 ISO 8859-8 拉丁文与希伯来文 ISO 8859-9 为土耳其文修正的Latin-1(Latin-5) ISO 8859-10 拉普人、北欧与爱斯基摩人的文字(Latin-6) ISO 8859-11 拉丁文与泰文 ISO 8859-13 波罗的海周边语系,例如拉脱维亚文等(Latin-7) ISO 8859-14 凯尔特文,例如盖尔文、威尔士文等(Latin-8) ISO 8859-15 改进的Latin-1,增加遗漏的法文、芬兰文字符和欧元符号(Latin-9) ISO 8859-16 罗马尼亚文(Latin-10) 其中缺少的编号12据说是为了预留给天城体梵文字母(Deva-nagari)的。印地文和尼泊尔文都使用了这种在七世纪形成的字母表。由于印度定义了自己的编码ISCII(Indian Script Code for Information Interchange),所以这个编号就未被使用。ISO 8859系列字符集都是单字节字符集,即只使用0x00-0xFF对字符编码。大家都知道ASCII吧,那么大家知道ANSI X3.4和ISO 646吗?在1968年发布的ANSI X3.4和1972年发布的ISO 646就是ASCII编码,只不过是不同组织发布的。绝大多数字符集都与ASCII编码保持兼容,ISO 8859系列字符集也不例外,它们的0x00-0x7f都与ASCII码保持一致,各字符集的不同之处在于如何利用0x80-0xff的码位。使用UniToy可以查看ISO 8859系列所有字符集的编码,例如:通过这些演示,大家是不是觉得代码页和字符集都是很简单、朴实的东西呢?好,在进入Unicode的话题前,让我们先看一个很深奥的概念。 3 字符编码模型程序员经常会面对复杂的问题,而降低复杂性的最简单的方法就是分而治之。Peter Constable在他的文章&Character set encoding basics Understanding character set encodings and legacy encodings&中描述了字符编码的四层模型。我觉得这种说法确实可以更清晰地展现字符编码中发生的事情,所以在这里也介绍一下。 3.1 字符的范围(Abstract character repertoire)设计字符编码的第一层就是确定字符的范围,即要支持哪些字符。有些编码方案的字符范围是固定的,例如ASCII、ISO 8859 系列。有些编码方案的字符范围是开放的,例如Unicode的字符范围就是世界上所有的字符。3.2 用数字表示字符(Coded character set)设计字符编码的第二层是将字符和数字对应起来。可以将这个层次理解成数学家(即从数学角度)看到的字符编码。数学家看到的字符编码是一个正整数。例如在Unicode中:汉字“字”对应的数字是23383。汉字“”对应的数字是134192。在写html文件时,可以通过输入&字&来插入字符“字”。不过在设计字符编码时,我们还是习惯用16进制表示数字。即将23383写成0x5BD7,将134192写成0x20C30。3.3 用基本数据类型表示字符(Character encoding form)设计字符编码的第三层是用编程语言中的基本数据类型来表示字符。可以将这个层次理解成程序员看到的字符编码。在Unicode中,我们有很多方式将数字23383表示成程序中的数据,包括:UTF-8、UTF-16、UTF-32。UTF是“UCS Transformation Format”的缩写,可以翻译成Unicode字符集转换格式,即怎样将Unicode定义的数字转换成程序数据。例如,“汉字”对应的数字是0x6c49和0x5b57,而编码的程序数据是:BYTE data_utf8[]={0xE6,0xB1,0x89,0xE5,0xAD,0x97}; // UTF-8编码WORD data_utf16[]={0x6c49,0x5b57};&&&&&&&&&&&&&&&&&&&&&&&&&&&&// UTF-16编码DWORD data_utf32[]={0x6c49,0x5b57};&&&&&&&&&&&&&&&&&&&&&&&& // UTF-32编码这里用BYTE、WORD、DWORD分别表示无符号8位整数,无符号16位整数和无符号32位整数。UTF-8、UTF-16、UTF-32分别以BYTE、WORD、DWORD作为编码单位。“汉字”的UTF-8编码需要6个字节。“汉字”的UTF-16编码需要两个WORD,大小是4个字节。“汉字”的UTF-32编码需要两个DWORD,大小是8个字节。4.2节会介绍将数字映射到UTF编码的规则。 3.4 作为字节流的字符(Character encoding scheme)字符编码的第四层是计算机看到的字符,即在文件或内存中的字节流。例如,“字”的UTF-32编码是0x5b57,如果用little endian表示,字节流是“57 5b 00 00”。如果用big endian表示,字节流是“00 00 5b 57”。字符编码的第三层规定了一个字符由哪些编码单位按什么顺序表示。字符编码的第四层在第三层的基础上又考虑了编码单位内部的字节序。UTF-8的编码单位是字节,不受字节序的影响。UTF-16、UTF-32根据字节序的不同,又衍生出UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE四种编码方案。LE和BE分别是Little Endian和Big Endian的缩写。3.5 小结通过四层模型,我们又把字符编码中发生的这些事情梳理了一遍。其实大多数代码页都不需要完整的四层模型,例如GB18030以字节为编码单位,直接规定了字节序列和字符的映射关系,跳过了第二层,也不需要第四层。4 再谈UnicodeUnicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。Unicode字符集可以简写为UCS(Unicode Character Set)。早期的Unicode标准有UCS-2、UCS-4的说法。UCS-2用两个字节编码,UCS-4用4个字节编码。UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行 (row),每行有256个码位(cell)。group 0的平面0被称作BMP(Basic Multilingual Plane)。将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。Unicode标准计划使用group 0 的17个平面: 从BMP(平面0)到平面16,即数字0-0x10FFFF。《谈谈Unicode编码》主要介绍了BMP的编码,本文将介绍完整的Unicode编码,并从多个角度浏览Unicode。本文的介绍基于Unicode 5.0.0版本。4.1 浏览Unicode先看一些数字:每个平面有2^16=65536个码位。Unicode计划使用了17个平面,一共有17*2个码位。其实,现在已定义的码位只有238605个,分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面15和平面16上只是定义了两个各占65534个码位的专用区(Private Use Area),分别是0xF0000-0xFFFFD和0xx10FFFD。所谓专用区,就是保留给大家放自定义字符的区域,可以简写为PUA。平面0也有一个专用}

我要回帖

更多关于 编写字符串复制函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信