不同字符集转换为unicode和显示当前系统支持的代码页
2008-01-20 00:52:30| 分类: 默认分类 | 标签: |字号大中小 订阅
【原创】
在写一个可以将不同字符集的字符串转换为unicode的函数,(为什么会有不同字符集的字符串?从网上抓下来的网页字符集千奇百怪,按"rb"读进来的时候就产生了不同字符集的字符串,呵呵)查了些资料,总算有些眉目。什么是mbstr什么是unicode我也不解释了,主要是写给自己看,怕忘了。具体实现不外乎两种:
1、利用windows API函数MultiByteToWideChar,函数原型如下:
int MultiByteToWideChar( UINT CodePage, // code page DWORD dwFlags, // character-type options LPCSTR lpMultiByteStr, // string to map int cbMultiByte, // number of bytes in string LPWSTR lpWideCharStr, // wide-character buffer int cchWideChar // size of buffer );
具体我就不解释了,自己看msdn好了,关键是第一个参数 unsigned int codepage,这个指定了转换时所用的代码页,是必须正确设置的。
下面给一个例程:
// we want to convert an MBCS string in lpszA int nLen = MultiByteToWideChar(CP_ACP, 0,lpszA, -1, NULL, NULL); LPWSTR lpszW = new WCHAR[nLen]; MultiByteToWideChar(CP_ACP, 0, lpszA, -1, lpszW, nLen); // use it to call OLE here pI->SomeFunctionThatNeedsUnicode(lpszW); // free the string delete[] lpszW;
这个例子中的CP_ACP是个常量,代表ANSI code page
这个例程还可以改进,你可以看到这里调用了两次MultiByteToWideChar,第一次是估计长度的,其实没有必要,一
个多字节字符对应顶多一个宽字符,所以我们简单的把多字节字符长度*2就好了,虽然会有些浪费,但效率有所提
高,或者还有一个做法,用c函数_mbstrlen()来获得准确字符个数,这个待会儿说
上面这个例程有些偏长,如果你频繁需要在多字节字符串和unicode之间转换的话,还可以利用ATL的转换宏
A2CW (LPCSTR) -> (LPCWSTR) A2W (LPCSTR) -> (LPWSTR) W2CA (LPCWSTR) -> (LPCSTR) W2A (LPCWSTR) -> (LPSTR)
注意要包含AFXPRIV.H,并声明USES_CONVERSION; 具体解释和优点我前一篇日志里有
但是这个宏不方便的地方在于无法指定代码页,那就只能在当前代码页字符串和unicode之间转换了
2、利用C函数mbstowcs
函数原型:
size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );
具体解释自己参看msdn
注意到这里没有让你设置代码页的参数,怎么办?
你需要调用另一个函数setlocal,原型如下:
char *setlocale( int category, const char *locale );
其中,第一个参数是你所设置的locale影响的类别,大概有时间啊货币啊字符啊什么的,嫌麻烦的话赋值为LC_ALL好了,后一个参数指名了代码页,具体是这样的
locale :: "lang[_country[.code_page]]" | ".code_page" | "" | NULL 可以设置 lang country 或者code_page,对于我们所关心的不同字符集而言,code_page是我们要设置的,那这个code_page该怎么设置呢?怎么样获得当前的代码页和系统支持的代码页,找了写资料,windowsAPI提供了这样的函数,下面是例程:
#include <windows.h> #include <stdio.h>
UINT CALLBACK EnumCodePagesProc(char *lpCodePagesString) { printf("支持:%s 代码页\n",lpCodePagesString); return true; } void main() { printf("当前代码页为:%d\n",GetACP()); EnumSystemCodePages(&EnumCodePagesProc,CP_SUPPORTED); } 具体不解释了,自己参考msdn
//一段小插曲:msdn上说EnumCodePagesProc这个回调函数应该是bool型的,结果一编译出错,应该是UINT型的,呵
但是这样获得的都是一些整数值,怎么知道具体对应那些编码呢,嘿嘿,这个对应表也让我找到了,po出来
37 | IBM037 | IBM EBCDIC(美国 - 加拿大) | |
437 | IBM437 | OEM 美国 | |
500 | IBM500 | IBM EBCDIC(国际) | |
708 | ASMO-708 | ||
720 | DOS-720 | 阿拉伯字符 (DOS) | |
737 | ibm737 | 希腊字符 (DOS) | |
775 | ibm775 | 波罗的海字符 (DOS) | |
850 | ibm850 | 西欧字符 (DOS) | |
852 | ibm852 | 中欧字符 (DOS) | |
855 | IBM855 | OEM 西里尔语 | |
857 | ibm857 | 土耳其字符 (DOS) | |
858 | IBM00858 | OEM 多语言拉丁语 I | |
860 | IBM860 | 葡萄牙语 (DOS) | |
861 | ibm861 | 冰岛语 (DOS) | |
862 | DOS-862 | 希伯来字符 (DOS) | |
863 | IBM863 | 加拿大法语 (DOS) | |
864 | IBM864 | 阿拉伯字符 (864) | |
865 | IBM865 | 北欧字符 (DOS) | |
866 | cp866 | 西里尔字符 (DOS) | |
869 | ibm869 | 现代希腊字符 (DOS) | |
870 | IBM870 | IBM EBCDIC(多语言拉丁语 2) | |
874 | windows-874 | 泰语 (Windows) | |
875 | cp875 | IBM EBCDIC(现代希腊语) | |
932 | shift_jis | 日语 (Shift-JIS) | |
936 | gb2312 | 简体中文 (GB2312) | * |
949 | ks_c_5601-1987 | 朝鲜语 | |
950 | big5 | 繁体中文 (Big5) | |
1026 | IBM1026 | IBM EBCDIC(土耳其拉丁语 5) | |
1047 | IBM01047 | IBM 拉丁语 1 | |
1140 | IBM01140 | IBM EBCDIC(美国 - 加拿大 - 欧洲) | |
1141 | IBM01141 | IBM EBCDIC(德国 - 欧洲) | |
1142 | IBM01142 | IBM EBCDIC(丹麦 - 挪威 - 欧洲) | |
1143 | IBM01143 | IBM EBCDIC(芬兰 - 瑞典 - 欧洲) | |
1144 | IBM01144 | IBM EBCDIC(意大利 - 欧洲) | |
1145 | IBM01145 | IBM EBCDIC(西班牙 - 欧洲) | |
1146 | IBM01146 | IBM EBCDIC(英国 - 欧洲) | |
1147 | IBM01147 | IBM EBCDIC(法国 - 欧洲) | |
1148 | IBM01148 | IBM EBCDIC(国际 - 欧洲) | |
1149 | IBM01149 | IBM EBCDIC(冰岛语 - 欧洲) | |
1200 | utf-16 | Unicode | * |
1201 | UnicodeFFFE | Unicode (Big-Endian) | * |
1250 | windows-1250 | 中欧字符 (Windows) | |
1251 | windows-1251 | 西里尔字符 (Windows) | |
1252 | Windows-1252 | 西欧字符 (Windows) | * |
1253 | windows-1253 | 希腊字符 (Windows) | |
1254 | windows-1254 | 土耳其字符 (Windows) | |
1255 | windows-1255 | 希伯来字符 (Windows) | |
1256 | windows-1256 | 阿拉伯字符 (Windows) | |
1257 | windows-1257 | 波罗的海字符 (Windows) | |
1258 | windows-1258 | 越南字符 (Windows) | |
1361 | Johab | 朝鲜语 (Johab) | |
10000 | macintosh | 西欧字符 (Mac) | |
10001 | x-mac-japanese | 日语 (Mac) | |
10002 | x-mac-chinesetrad | 繁体中文 (Mac) | |
10003 | x-mac-korean | 朝鲜语 (Mac) | * |
10004 | x-mac-arabic | 阿拉伯字符 (Mac) | |
10005 | x-mac-hebrew | 希伯来字符 (Mac) | |
10006 | x-mac-greek | 希腊字符 (Mac) | |
10007 | x-mac-cyrillic | 西里尔字符 (Mac) | |
10008 | x-mac-chinesesimp | 简体中文 (Mac) | * |
10010 | x-mac-romanian | 罗马尼亚语 (Mac) | |
10017 | x-mac-ukrainian | 乌克兰语 (Mac) | |
10021 | x-mac-thai | 泰语 (Mac) | |
10029 | x-mac-ce | 中欧字符 (Mac) | |
10079 | x-mac-icelandic | 冰岛语 (Mac) | |
10081 | x-mac-turkish | 土耳其字符 (Mac) | |
10082 | x-mac-croatian | 克罗地亚语 (Mac) | |
20000 | x-Chinese-CNS | 繁体中文 (CNS) | |
20001 | x-cp20001 | TCA 台湾 | |
20002 | x-Chinese-Eten | 繁体中文 (Eten) | |
20003 | x-cp20003 | IBM5550 台湾 | |
20004 | x-cp20004 | TeleText 台湾 | |
20005 | x-cp20005 | Wang 台湾 | |
20105 | x-IA5 | 西欧字符 (IA5) | |
20106 | x-IA5-German | 德语 (IA5) | |
20107 | x-IA5-Swedish | 瑞典语 (IA5) | |
20108 | x-IA5-Norwegian | 挪威语 (IA5) | |
20127 | us-ascii | US-ASCII | * |
20261 | x-cp20261 | T.61 | |
20269 | x-cp20269 | ISO-6937 | |
20273 | IBM273 | IBM EBCDIC(德国) | |
20277 | IBM277 | IBM EBCDIC(丹麦 - 挪威) | |
20278 | IBM278 | IBM EBCDIC(芬兰 - 瑞典) | |
20280 | IBM280 | IBM EBCDIC(意大利) | |
20284 | IBM284 | IBM EBCDIC(西班牙) | |
20285 | IBM285 | IBM EBCDIC(英国) | |
20290 | IBM290 | IBM EBCDIC(日语片假名) | |
20297 | IBM297 | IBM EBCDIC(法国) | |
20420 | IBM420 | IBM EBCDIC(阿拉伯语) | |
20423 | IBM423 | IBM EBCDIC(希腊语) | |
20424 | IBM424 | IBM EBCDIC(希伯来语) | |
20833 | x-EBCDIC-KoreanExtended | IBM EBCDIC(朝鲜语扩展) | |
20838 | IBM-Thai | IBM EBCDIC(泰语) | |
20866 | koi8-r | 西里尔字符 (KOI8-R) | |
20871 | IBM871 | IBM EBCDIC(冰岛语) | |
20880 | IBM880 | IBM EBCDIC(西里尔俄语) | |
20905 | IBM905 | IBM EBCDIC(土耳其语) | |
20924 | IBM00924 | IBM 拉丁语 1 | |
20932 | EUC-JP | 日语(JIS 0208-1990 和 0212-1990) | |
20936 | x-cp20936 | 简体中文 (GB2312-80) | * |
20949 | x-cp20949 | 朝鲜语 Wansung | * |
21025 | cp1025 | IBM EBCDIC(西里尔塞尔维亚 - 保加利亚语) | |
21866 | koi8-u | 西里尔字符 (KOI8-U) | |
28591 | iso-8859-1 | 西欧字符 (ISO) | * |
28592 | iso-8859-2 | 中欧字符 (ISO) | |
28593 | iso-8859-3 | 拉丁语 3 (ISO) | |
28594 | iso-8859-4 | 波罗的海字符 (ISO) | |
28595 | iso-8859-5 | 西里尔字符 (ISO) | |
28596 | iso-8859-6 | 阿拉伯字符 (ISO) | |
28597 | iso-8859-7 | 希腊字符 (ISO) | |
28598 | iso-8859-8 | 希伯来字符 (ISO-Visual) | * |
28599 | iso-8859-9 | 土耳其字符 (ISO) | |
28603 | iso-8859-13 | 爱沙尼亚语 (ISO) | |
28605 | iso-8859-15 | 拉丁语 9 (ISO) | |
29001 | x-Europa | 欧罗巴 | |
38598 | iso-8859-8-i | 希伯来字符 (ISO-Logical) | * |
50220 | iso-2022-jp | 日语 (JIS) | * |
50221 | csISO2022JP | 日语(JIS- 允许 1 字节假名) | * |
50222 | iso-2022-jp | 日语(JIS- 允许 1 字节假名 - SO/SI) | * |
50225 | iso-2022-kr | 朝鲜语 (ISO) | * |
50227 | x-cp50227 | 简体中文 (ISO-2022) | * |
51932 | euc-jp | 日语 (EUC) | * |
51936 | EUC-CN | 简体中文 (EUC) | * |
51949 | euc-kr | 朝鲜语 (EUC) | * |
52936 | hz-gb-2312 | 简体中文 (HZ) | * |
54936 | GB18030 | 简体中文 (GB18030) | * |
57002 | x-iscii-de | ISCII 梵文 | * |
57003 | x-iscii-be | ISCII 孟加拉语 | * |
57004 | x-iscii-ta | ISCII 泰米尔语 | * |
57005 | x-iscii-te | ISCII 泰卢固语 | * |
57006 | x-iscii-as | ISCII 阿萨姆语 | * |
57007 | x-iscii-or | ISCII 奥里雅语 | * |
57008 | x-iscii-ka | ISCII 卡纳达语 | * |
57009 | x-iscii-ma | ISCII 马拉雅拉姆语 | * |
57010 | x-iscii-gu | ISCII 古吉拉特语 | * |
57011 | x-iscii-pa | ISCII 旁遮普语 | * |
65000 | utf-7 | Unicode (UTF-7) | * |
65001 | utf-8 | Unicode (UTF-8) | * |
65005 | utf-32 | Unicode (UTF-32) | * |
65006 | utf-32BE | Unicode (UTF-32 Big-Endian) | * |
看到了吧,我们的汉语是936,utf_8是65001,这下你可以把这个整数值写到setlocale中,然后调用mbswcs就可以了。
给个GB编码文件的例程:
FILE *in=fopen(fname, "rb");
long length=_filelength(_fileno(in));
//包含在io.h中,获得文件的字符数
setlocale(LC_ALL, ".936");
char *MbText=new char[length+1];
//动态分配内存,长度为(length+1)*sizeof(char)
fread(MbText, sizeof(char), length, in);
MbText[length]='\0';
NumOfChar=_mbstrlen(MbText);
RawText=new wchar_t[NumOfChar+1];
mbstowcs(RawText, MbText, length)
RawText[NumOfChar]=L'\0';
delete []MbText;
哈哈,问题解决。
哦,还有个如何获取字符串长度的问题,
上面说过用_mbstrlen(),它会根据你设置的代码页进行字符验证,
得出准确的字符串长度,也就是字符个数
不同字符集转换为unicode问题基本解决,反方向呢?那自然有反方向的函数,道理一样,自己到msdn上看吧。