UNICODE字符串和ANSI字符的转换

     windows把字符串分成两类,UNICODE字符串和基于code page的ANSI字符串。UNICDOE字符串使用UTF-16LE编码方式(占2字节,其值与UNICODE编码真值一致,暂不考虑位于BMP之外的情况)。ANSI字符串使用多字节编码方式,以简体中文GBK为例(code page 936),ASCII码使用1字节,中文使用2字节,使用leadbyte来区分两者。

    在C/C++程序(VS2010)里,UNICODE字符串对应wchar_t,ANSI字符串对应char。比如字符串 L"汉" 的二进制值是0x6c49,与UNICODE编码真值一致。字符串 "汉" 的二进制值是0xba,0xba,与GBK编码真值一致。

    在字符串操作中,有时需要在UNICODE字符串和ANSI字符串之间进行转换。下面以输出一个字符串到文本文件为例,讲讲这个转换过程(输出到console稍微有点特殊,后面讨论)。根据输出操作中源和目标的字符串模式,可以分成以下4种情况:

    情况1,源为ANSI模式,目标为ANSI模式。

        这是我们最常用的情况,源和目标模式一致,无需转换。

  ...
  fputs("abc汉字", fp);
  ...

        在上面的代码里,源是ANSI字符串"abc汉字",以默认方式打开的目标fp也是ANSI模式。

    情况2,源为ANSI模式,目标为UNICODE模式。

        这种情况是不允许的,从微软代码的注释来看,是为了防止ANSI系列函数操作UNICODE文件。

    情况3,源为UNICODE模式,目标为ANSI模式。

        为了使源为UNICODE模式,我们只能使用wchar_t字符串,比如下面的代码:

  ...
  fputws(L"abc汉字", fp);
  ...

        源是UNICODE字符串(UTF-16LE编码方式),以默认方式打开的目标fp是ANSI模式。

        通过调用wctomb函数把UNICODE字符串转成基于code page的ANSI字符串,这也是目标fp可以接受的字符串。

        wctomb函数的行为是跟locale相关的,如果是c locale,它会逐个判断wchar_t,如果值大于255,则是出错,否则强制转换成char;如果不是c locale,比如chinese locale,它会以该locale对应的code page(比如936)为参数调用WideCharToMultiByte进行转换。

    情况4,源为UNICODE模式,目标为UNICODE模式。

        做为源使用的wchar_t字符串,其编码模式是UTF-16LE。做为目标,则有两种选择,UTF-16LE和UTF-8。

  ...
  fp = fopen("a.txt", "w,ccs=UTF-16LE");
  fputs(L"abc汉字", fp);
  ...
  fp = fopen("a.txt", "w,ccs=UTF-8");
  fputs(L"abc汉字", fp);
  ...

        如果目标是UTF-16LE编码模式,则与源是一致的,无需转换。如果目标是UTF-8编码模式,则需要以UTF-8 code page为参数调用WideCharToMultiByte进行转换。

 

    上面是操作普通文本文件,接下来是操作console,同样可以分成4种情况:

    情况1,源为ANSI模式,目标为ANSI模式。

        虽然源和目标模式一致,但还需要根据locale进行不同处理。如果是c locale,则无需转换,直接写入(用WriteFile写到console对应的句柄)。否则,需要分两步处理。第一步,调用mbtowc将源字符串(ANSI模式)转成临时的UNICODE字符串(UTF-16LE)。第二步,以console code page为参数调用WideCharToMultiByte将临时的UNICODE字符串转成目标字符串(ANSI模式),再写入(WriteFile)。

        这里需要注意,虽然都是ANSI模式,但源字符串是基于相应locale的code page,目标字符串是基于console的code page(这两个code page往往是一样的)。

        mbtowc的行为是locale相关的,如果是c locale,则将char强制转成wchar_t(在上面的第一步中,显然不会遇到这种情况)。否则,以相应locale的code page为参数调用MultiByteToWideChar进行转换,将ANSI字符串转成UNICODE字符串(UTF-16LE)。

    情况2,源为ANSI模式,目标为UNICODE模式。

        这种情况也是不允许的。

    情况3,源为UNICDOE模式,目标为ANSI模式。

        这里的源字符串也只能是UTF-16LE编码方式。如果是c locale,则逐个判断wchar_t,值大于255是出错,否则强制转成char写入(WriteFile)。如果不是c locale,这是最复杂的一种情况,需要经过三次转换:

        首先,以相应locale的code page为参数调用WideCharToMultiByte将源字符(UNICODE模式)串转成临时的ANSI字符串。

        接着,调用mbtowc将临时的ANSI字符串转成临时的UNICODE字符串(这个字符串其实跟源字符串是一致的,但代码的流程就是这样走的)。

        最后,以console code page为参数调用WideCharToMultiByte将临时的UNICODE字符串转成目标字符串(ANSI模式),再写入(WriteFile)。最后这两步与情况1的两步是一样的。

    情况4,源为UNICODE模式,目标为UNICODE模式。

        做为源使用的wchar_t字符串,其编码模式是UTF-16LE。做为目标,则有两种编码模式,UTF-16LE和UTF-8。无需区分这两种情况,windows已经帮我们处理好了,直接调用WriteConsoleW写入。

  ...
  _setmode(_fileno(stdout), _O_U16TEXT);
  fputws(L"1汉1", stdout);
  ...
  _setmode(_fileno(stdout), _O_U8TEXT);
  fputws(L"1汉1", stdout);
  ...
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值