快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

Unicode快速指引

  最近在弄的一个东西,由于一开始就没有规范好字符编码,结果遇到不少的困扰。《Windows核心编程》第一章就是讲字符编码,可见这东西的重要。于是痛定思痛,决定用UTF-8统一所有内部编码。重温了一些知识,整理出来备忘。

  1,简介

  Unicode学名"Universal Multiple-Octet Coded Character Set",简称UCS,是一套由国际组织维护的字符编码。UCS为现存的每一个字符都赋予一个唯一码值(code point),通常表示为U+xxxx,其中xxxx为对应的16进制码值

  UCS有两种格式:UCS-2 和 UCS-4。UCS-2为2字节编码,范围从U+0000~U+FFFF;UCS-4为4字节编码,范围从U+00000000~U+7FFFFFFFF。目前Unicode4.0标准中,U+0000~U+FFFF区间已经包含了世界上所有语言的常用文字,简称BMP(Basic Multilingual Plane),加上其它的特殊符号扩展,最高也只用到了U+0010FFFF

  2,UTF编码

  UCS字符在计算机中的表示方式常用的有UTF-8,UTF-16,UTF-32。UTF-32用32位来表示单个UCS字符,跟UCS-4的码值一一对应。UTF-16以16位为单元来编码UCS字符,U+0000~U+FFFF范围内用单个16位值来表示,跟UCS-2一一对应,而U+10000~U+10FFFF范围内的字符则需要用2个连续的16位值来表示;UTF-8以8位为单元进行编码,跟UTF-16类似,需要用到1~6个连续的8位值来表示单个UCS字符(实际上由于目前UCS最高只用到了U+10FFFF,所以UTF-8编码的单个字符的长度不会超过4Byte)。具体算法如下表所示

  UCS-4到UTF-16的转换表:

  U+00000000~U+0000FFFF

  xxxxxxxxxxxxxxxx

  xxxxxxxxxxxxxxxx

  U+00010000~U+0010FFFF

  000uuuuuxxxxxxxxxxxxxxxx 110110wwwwxxxxxx 110111xxxxxxxxxx

  注1:wwww=uuuuu-1

  注2:U+DB00(1101100000000000)~U+DBFF(110110FFFFFFFFFF)称为High Surrogate,U+DC00(1101110000000000)~U+DFFF(110111FFFFFFFFFF)称为Low Surrogate。Surrogate区间只用于UTF-16中表示BMP之外的字符。BMP中除Surrogate之外的也被称为character's scalar value

  UCS-4到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

  3,BOM

  UTF-16和UTF-32都有字节序的问题,需要区分big endian和little endian。通常这两种编码的文件都会在开头额外添加一个U+FEFF字符。因为FFFE是UCS中不存在的字符,在实际中不应该出现,这样在读取文件的时候首先检测一下,如果是FEFF,就表明是Big-Endian的;如果是FFFE,就表明是Little-Endian的。这个就称为BOM(Byte Order Mark)。

  UTF-8无字节序的问题,但也可以加上BOM来表明编码方式。U+FEFF的UTF-8编码是EF BB BF,如果在文件头读到这个,就表示该文件是UTF-8编码的

  4,跨平台

  Windows内部使用UTF-16编码,VC将单字节字符串常量编译成locale指定的本地编码(中文系统默认为GBK,可以通过编译器指令#pragma setlocale(LOC)来指定本地编码,但不支持UTF-8),wchar_t是16位,宽字节字符串常量用UTF-16进行编码。

  Linux内部用UTF-8编码,GCC将单字节字符串编译为UTF-8,wchar_t为32位,宽字节字符串常量用UCS-4编码

  MinGW下,单字节字符是utf-8编码的,但wchar_t跟VC一样是16位,宽字节字符串也是用UTF-16编码

  在我看来,考虑到跨平台的话,程序内部使用UTF-8编码是不错的选择

  另外,对于C源文件的编码方式,一般来说保存为UTF-8会更好,这样即使里面包含中文字符,其它国家或地区的程序员打开你的文件也不会看到乱码。但遗憾的是,虽然VC和GCC都支持UTF-8,但前者只能识别带BOM的,后者不能有BOM,残念...

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论