以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  MFC下Unicode到UTF-8格式的转换  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=27008)


--  作者:卷积内核
--  发布时间:2/7/2006 8:51:00 AM

--  MFC下Unicode到UTF-8格式的转换

●MFC一般编程习惯到 UNICODE宽字节字符集编程
UNICODE 通过用双字节来表示一个字符,从而在更大范围内将数字代码映射到多种语言的字符集。


MFC 以宏的形式提供了将一般文本转换成 UNICODE 数据类型的途径。
开发人员只需要稍微改变一下编写代码的习惯便可以轻松编写支持 UNICODE 的应用。

定义部分:
通用 多字节 宽字节
_TCHAR/TCHAR char wchar_t
_T 或_TEXT char 常量字符串 wchar_t 常量字符串 L
LPTSTR char *(或win32下LPSTR) wchar_t *
LPCTSTR const char * LPCSTR const wchar_t *


通用形式就是自动的判断当前是否定义了_UNICODE字符集,

例 如果是的话

typedef wchar_t TCHAR;

不是的话
typedef char TCHAR;


例:
MFC中CString 类也通过一种通用定义形式

通用形式下
typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;
宽字节字符集
typedef ATL::CStringT< wchar_t, StrTraitMFC< wchar_t > > CStringW;
ANSI节字符集
typedef ATL::CStringT< char, StrTraitMFC< char > > CStringA;


操作系统对UNICODE的支持
Win98 只支持ANSI
win2000 支持ANSI 支持UNICODE
wince 只支持UNICODE


●UNICODE 转换到 UTF-8
UTF-8 编码字符理论上可以最多到 6 个字节长
注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目.


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


我使用的函数:

/*-------------------------------------------------------------------------------------
wchar_t (UNICODE 2bit)->char (UTF-8)(multi bit )
它通过简单的码位析取与分配即可完成.

本函数提供这一实现.
dest_str:
宽字节字符转换为UTF-8编码字符的目标地址.
src_wchar:被转换的宽字节源字符.
返回值:
返回实际转换后的字符的字节数. 若遇到错误或检测到非法字节序列, 则返回-1.

注意! 传递进来的宽字符应是能被合法转换为UTF-8编码的字符.
--------------------------------------------------------------------------------------
*/

size_t g_f_wctou8(char * dest_str, const wchar_t src_wchar)
{
int count_bytes = 0;
wchar_t byte_one = 0, byte_other = 0x3f; // 用于位与运算以提取位值 0x3f--->00111111
unsigned char utf_one = 0, utf_other = 0x80; // 用于"位或"置标UTF-8编码 0x80--->1000000
wchar_t tmp_wchar = L’0’; // 用于宽字符位置析取和位移(右移6位)
unsigned char tmp_char = ’0’;

if (!src_wchar)//
return (size_t)-1;

for (;;) // 检测字节序列长度
{
if (src_wchar <= 0x7f){ // <=01111111
count_bytes = 1; // ASCII字符: 0xxxxxxx( ~ 01111111)
byte_one = 0x7f; // 用于位与运算, 提取有效位值, 下同
utf_one = 0x0;
break;
}
if ( (src_wchar > 0x7f) && (src_wchar <= 0x7ff) ){ // <=0111,11111111
count_bytes = 2; // 110xxxxx 10xxxxxx[1](最多11个1位, 简写为11*1)
byte_one = 0x1f; // 00011111, 下类推(1位的数量递减)
utf_one = 0xc0; // 11000000
break;
}
if ( (src_wchar > 0x7ff) && (src_wchar <= 0xffff) ){ //0111,11111111<=11111111,11111111
count_bytes = 3; // 1110xxxx 10xxxxxx[2](MaxBits: 16*1)
byte_one = 0xf; // 00001111
utf_one = 0xe0; // 11100000
break;
}
if ( (src_wchar > 0xffff) && (src_wchar <= 0x1fffff) ){ //对UCS-4的支持..
count_bytes = 4; // 11110xxx 10xxxxxx[3](MaxBits: 21*1)
byte_one = 0x7; // 00000111
utf_one = 0xf0; // 11110000
break;
}
if ( (src_wchar > 0x1fffff) && (src_wchar <= 0x3ffffff) ){
count_bytes = 5; // 111110xx 10xxxxxx[4](MaxBits: 26*1)
byte_one = 0x3; // 00000011
utf_one = 0xf8; // 11111000
break;
}
if ( (src_wchar > 0x3ffffff) && (src_wchar <= 0x7fffffff) ){
count_bytes = 6; // 1111110x 10xxxxxx[5](MaxBits: 31*1)
byte_one = 0x1; // 00000001
utf_one = 0xfc; // 11111100
break;
}
return (size_t)-1; // 以上皆不满足则为非法序列
}
// 以下几行析取宽字节中的相应位, 并分组为UTF-8编码的各个字节
tmp_wchar = src_wchar;
for (int i = count_bytes; i > 1; i--)
{ // 一个宽字符的多字节降序赋值
tmp_char = (unsigned char)(tmp_wchar & byte_other);///后6位与byte_other 00111111
dest_str[i - 1] = (tmp_char | utf_other);/// 在前面加10----跟10000000或
tmp_wchar >>= 6;//右移6位
}
//这个时候i=1
//对UTF-8第一个字节位处理,
//第一个字节的开头"1"的数目就是整个串中字节的数目
tmp_char = (unsigned char)(tmp_wchar & byte_one);//根据上面附值得来,有效位个数
dest_str[0] = (tmp_char | utf_one);//根据上面附值得来 1的个数
// 位值析取分组__End!
return count_bytes;
}
/*------------------------------------------------------------------------
* 通过g_f_wctou8函数实现 CString (UNICODE下 ) 到 char *(UTF-8) 的转换
* wstr 为要转换的UNICODE-16的CString的一个引用
* *p 为存UTF-8格式的地址
*
目前我的做法是:
* 循环将CString 中的宽字符 利用上面的g_f_wctou8()来转换,并存到char *p中

* 这里的char *p是 要传给Client SDK,出来的格式就是UTF-8格式的
*

*-------------------------------------------------------------------------
*/
int g_f_wcs_to_pchar(CString& wstr,char * p)
{
wchar_t wc=L’1’;
char c[10]="1";//申请一个缓存
size_t r=0; //size_t unsigned integer Result of sizeof operator
int i=0;
int j=0;
for(i=0;i
{
wc=wstr.GetAt(i);//得到一个宽字符
r=g_f_wctou8(c,wc);//将一个宽字符按UTF-8格式转换到p地址
if(r==-1)//出错判断
AfxMessageBox(_T("wcs_to_pchar error"));
p[j]=c[0];//第一个值附给p
j++;
if(r>1)
{
for(size_t x=1;x
{
p[j]=c[x];
j++;
}
}
}
p[j]=’0’;
return 1;
}
/*-----------------------------------------------------------------------------
char *-->wchar_t
它通过简单的码位截取与合成即可完成.
本函数提供这一实现.
dest_wchar:
保存转换后的宽字节字符目标地址.
src_str:
被转换的UTF-8编码源字符的多字节序列.
返回值:
返回被转换的字符的字节数. 若遇到错误或检测到非法字节序列, 则返回-1.

注意! 传递进来的宽字符应是能被合法转换为UTF-8编码的字符.
------------------------------------------------------------------------------*/
size_t g_f_u8towc(wchar_t &dest_wchar, const unsigned char * src_str)
{
int count_bytes = 0;
unsigned char byte_one = 0, byte_other = 0x3f; // 用于位与运算以提取位值 0x3f-->00111111
wchar_t tmp_wchar = L’0’;

if (!src_str)
return (size_t)-1;

for (;;) // 检测字节序列长度,根据第一个字节头的1个个数
{
if (src_str[0] <= 0x7f){
count_bytes = 1; // ASCII字符: 0xxxxxxx( ~ 01111111)
byte_one = 0x7f; // 用于位与运算, 提取有效位值, 下同 01111111
break;
}
if ( (src_str[0] >= 0xc0) && (src_str[0] <= 0xdf) ){
count_bytes = 2; // 110xxxxx(110 00000 ~ 110 111111)
byte_one = 0x1f; //00011111 第一字节有效位的个数
break;
}
if ( (src_str[0] >= 0xe0) && (src_str[0] <= 0xef) ){
count_bytes = 3; // 1110xxxx(1110 0000 ~ 1110 1111)
byte_one = 0xf; //00001111
break;
}
if ( (src_str[0] >= 0xf0) && (src_str[0] <= 0xf7) ){
count_bytes = 4; // 11110xxx(11110 000 ~ 11110 111)
byte_one = 0x7;
break;
}
if ( (src_str[0] >= 0xf8) && (src_str[0] <= 0xfb) ){
count_bytes = 5; // 111110xx(111110 00 ~ 111110 11)
byte_one = 0x3;
break;
}
if ( (src_str[0] >= 0xfc) && (src_str[0] <= 0xfd) ){
count_bytes = 6; // 1111110x(1111110 0 ~ 1111110 1)
byte_one = 0x1;
break;
}
return (size_t)-1; // 以上皆不满足则为非法序列
}
// 以下几行析取UTF-8编码字符各个字节的有效位值
//先得到第一个字节的有效位数据
tmp_wchar = src_str[0] & byte_one;
for (int i=1; i
{
tmp_wchar <<= 6; // 左移6位后与后续字节的有效位值"位或"赋值
tmp_wchar = tmp_wchar | (src_str[i] & byte_other);//先与后或
}
// 位值析取__End!
dest_wchar = tmp_wchar;
return count_bytes;
}
/*-------------------------------------------------------------------------
目的 :实现 UTF-8格式 的(char *) p->(UNICODE 下 CString )wstr 的转化
循环利用g_f_u8towc()这个函数来把char *p转换成宽字符,再存到CString 中!
----------------------------------------------------------------------------
*/
CString g_f_pchar_to_wcs(const unsigned char * p )
{
CString wstr(_T(""));
wchar_t wc=L’1’;
size_t r=0; //size_t unsigned integer Result of sizeof operator
while (1)
{
if(*p==NULL||*p==’0’)//如果为空或者结束则为跳出循环
break;
r=g_f_u8towc(wc,p);//从UTF-8格式的地址中,读一个wchar_t出来
if(r==-1)//出现错误
AfxMessageBox(_T("g_f_u8towc error"));
p=p+r; //移位,准备下一次的转换
wstr+=wc;//给CString 附值
}

return wstr;

}



W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
46.875ms