中文字符编码之GBK,UTF-16和UTF-8

编程中经常会遇到这三种字符编码形式的相互转换问题,以至于许多第三方的库不明原因的调用失败,其实很多都是由于第三方库支持的是utf-8而不是windows默认支持的utf-16导致的。

下面介绍一下windows系统下常见的这三种字符编码方式。

GB2312

是我们国家自己国标的汉字编码字符集,该字符集以一个16位的2进制数据单元表示一个汉字,所以能够将两个char型数据单元保存一个汉字。

微软的Windows操作系统汉字的编码字符集支持GB2312。这就是为什么我们用:

constchar* pChar = “中文”;

printf(pChar);

能够正确显示中文的原因。

但是,假如我们现在要将程序转换为一种除了中文和标准ASCII字符之外的文字时(比如说韩文),由于韩文不能被GB2312解析,所以就会产生乱码。

这就是为什么微软推荐采用Unicode的原因。因为Unicode包含了所有人类已知的文字字符集,理论上可以解析所有文字。

 

Unicode

Unicode字符集实际上是国际标准 ISO 10646 的一个子集。Unicode字符集是由Unicode协会公布的

 

ISO 10646定义了 通用字符集 (Universal Character Set, UCS). UCS 是所有其他字符集标准的一个超集。ISO10646 定义了一个 31 位的字符集. 然而, 在这巨大的编码空间中, 迄今为止只分配了前 65534 个码位(0x0000 0xFFFD). 这个 UCS 16位子集称为基本多语言面 (Basic Multilingual Plane, BMP). 将被编码在 16 BMP 以外的字符都属于非常特殊的字符(比如象形文字), 且只有专家在历史和科学领域里才会用到它们.

 

 UTF-16

UCS Unicode 只是分配整数给字符的编码表.现在存在好几种将一串字符表示为一串字节的方法. 最显而易见的两种方法是将Unicode 文本存储为 2 4 个字节序列的串. 这两种方法的正式名称分别为 UCS-2 UCS-4. WindowsUnicode表示方式极为UCS-2,即用两个字节表示一个Unicode字符。

除非另外指定, 否则大多数的字节都是Bigendian convention. 将一个 ASCII Latin-1 的文件转换成 UCS-2 只需简单地在每个ASCII 字节前插入 0x00. 如果要转换成UCS-4, 则必须在每个 ASCII 字节前插入三个0x00.

Windows内部使用UCS-2标准,并用UTF-16实现。在基本多语言平面内定义的符号((Basic MultilingualPlane, BMP),或称第零平面(Plane 0)),使用2个字节表示。

所以,Windows中使用的wchar_t的单位为2个字节,一个ASCII字符也要用两个字节表示。

Java采用的也是UTF-16

 

UTF-8

Unix 下使用 UCS-2 (UCS-4) 会导致非常严重的问题. 用这些编码的字符串会包含一些特殊的字符, 比如'\0' '/', 它们在文件名和其他 C 库函数参数里都有特别的含义.另外,大多数使用ASCII 文件的 UNIX 下的工具, 如果不进行重大修改是无法读取 16 位的字符的. 基于这些原因, 在文件名, 文本文件, 环境变量等地方,UCS-2 不适合作为Unicode 的外部编码.

ISO10646-1 Annex R RFC 2279 里定义的UTF-8 编码没有这些问题. 它是在Unix 风格的操作系统下使用 Unicode 的明显的方法.

 

UTF-8有一下特性:

  • UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
  • 所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分.
  • 表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在 0x80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.
  • 可以编入所有可能的 231个 UCS 代码
  • UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.
  • Bigendian UCS-4 字节串的排列顺序是预定的.
  • 字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到.

注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目.

UTF-8web协议和Unix族的操作系统中广泛使用。ASCII不作变换, 其他字符做变长编码, 每个字符1-3byte.

 搞清了这三种编码方式,下面再谈一下如何相互转化的问题。

//wchar_t转成UTF-8     
inline string ConvertWChar2UTF8( const wchar_t* a_szSrc )     
{         
      
    const int nszBuffer = WideCharToMultiByte( CP_UTF8, 0, a_szSrc, -1, NULL, 0, NULL, NULL );     
    char* Buffer = new char[nszBuffer];  
    WideCharToMultiByte( CP_UTF8, 0, a_szSrc, -1, Buffer, nszBuffer, NULL, NULL );     
    string strReturn = Buffer;  
    delete[] Buffer;  
    return strReturn;  
} ;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值