您的位置:首页 > 其它

[转]有关UNICODE、ANSI字符集和相关字符串操作总结

2012-02-28 21:00 423 查看
听一个师兄说,在编程的过程中会有20%的时间花在字符处理上,不知道这个数据是否正确,但从自己的编程学习中的确觉得字符处理花费了自己较多的时间,在网上看到了这篇文章,正好解决了自己的一个小问题,保存下来有空一一研究一下。

Q  UNICODE字符串如何显示  

A 如果程序定义了_UNICODE宏直接用  

WCHAR  *str=L"unicodestring";  

TextOut(0,0,str);  

否则就需要转换类型  

#include  <comdef.h>  

WCHAR  *str=L"unicodestring";  

bstr_t  str1=str;  

TextOut(0,0,(char*)str1);  

 
Q  如何实现ANSI和UNICODE的相互转换  

A  将ANSI转换到Unicode  

(1)通过L这个宏来实现,例如:  CLSIDFromProgID(  L"MAPI.Folder",&clsid);  

(2)通过MultiByteToWideChar函数实现转换,例如:  

char  *szProgID  =  "MAPI.Folder";  

WCHAR  szWideProgID[128];  

CLSID  clsid;  

long  lLen  =  MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));  

szWideProgID[lLen]  =  '/0';    

(3)通过A2W宏来实现,例如:    

USES_CONVERSION;    

CLSIDFromProgID(  A2W(szProgID),&clsid);    

 

将Unicode转换到ANSI  

(1)使用WideCharToMultiByte,例如:  

//  假设已经有了一个Unicode  串  wszSomeString...    

char  szANSIString  [MAX_PATH];    

WideCharToMultiByte  (  CP_ACP,  WC_COMPOSITECHECK,  wszSomeString,  -1,  szANSIString,  sizeof(szANSIString),  NULL,  NULL  );    

(2)使用W2A宏来实现,例如:  

USES_CONVERSION;  

pTemp=W2A(wszSomeString);    

 

注意在转换时可能存在的问题:  

因为ANSI转UNICODE,如果使用A2W或MultiByteToWideChar(第一个参数是CP_ACP)的话,是根据系统默认的转码表,把转入的ANSI字符串看作Multi-Bytes字符串处理的,如果是中文(中文windows默认就是中文),一个大于0x87的byte可能和下一byte一起被看作一个汉字,然后根据汉字的Unicode编码转换为相同的Unicode汉字,如果找不到相应的编码,一般就用一个默认的字符来取代它(一般是问号“?”),由此看,如果随便把一段数据给他转,转化很复杂而且极可能不可逆,而且你加密过的ANSI码是相当混乱的有很多〉0x87的byte,转换就变得不可逆了。
 

建议自己直接就这样写:  

CHAR  lpANSI[COUNT];  

WCHAR  lpUnicode[COUNT];  

int  i  =  0;    

while(lpANSI[i]  !=  '/0'  )  {  

       lpUnicode[i]  =  (WCHAR)lpANSI[i];  

}  

lpUnicode[i]  =  L'/0';  

然后按相同的方法转回来,因为对于0~0x87的ANSI字符串,对应的Unicode码就是相同的16位值,至于其他的,你的字符串反正加了密,没必要转换成显示出来是一样的字符,就按同样的方法处理了,其实如果中间的字符串不用显示或别的,直接reutrn  (LPWSTR)lpANSI;过去也可以,  反正接受的时候自己清楚就可以了。  

 
Q  如何让程序支持UNICODE    

A   NT系统的内核是unicode代码,通常vc分创建的工程默认都是ansi代码(可以兼容win9x),在nt下ansi程式在调用windows  API的时系统实际又进行了一次ansi到unicode的代码转化,如MoveWindowA实际上又调用MoveWindowW.如果以我们的程序不考虑win9x(早晚是明日黄花)的话,直接用unicode编译,那么程式的代码执行效率一定能增色不少.具体:  

(0).在vc编译选项上,在vc7.0以上在工程的属性页中的“字符集”选上"使用  Unicode  字符集"即可,在vc6.0下可能麻烦一点,得先把vc运行库的unicode版本复制到vc路径下,一般都是和xxx.lib的ansi对应xxxU.lib,默认装vc时是不会装的,将工程属性  

(0).1.改语言定义:  

在project  settings的"C++"页中的"preprocessor  definitions"中改_MBCS为_UNICODE  

(0).2.改入口函数:  

在"link"页中的"project  Options"加入/entry:"wWinMainCRTStartup"即可.  

 

(1)在代码上,处理字符中的多用TCHAR.H中的宏,如strcpy用_tcscpy代替,用TCHAR代char,  

用TCHAR  m_mystr[]=_T("xxxx")代替  char  m_mystr[]="xxxx";  

(2)注意调试UNICODE程序时,需要在安装时VC选择所有选项,否则会缺少动态库和相应的.lib文件  

 
Q  如何取得一个既包含单字节字符又包含双字节字符的字符串的字符个数?  

A  可以调用Microsoft  Visual  C++的运行期库包含函数_mbslen来操作多字节(既包括单字节也包括双字节)字符串。  调用strlen函数,无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。  

 
Q  如何对DBCS(双字节字符集)字符串进行操作?  

A 函数  描述  

PTSTR  CharNext  (  LPCTSTR  );  返回字符串中下一个字符的地址  

PTSTR  CharPrev  (  LPCTSTR,  LPCTSTR  );  返回字符串中上一个字符的地址  

BOOL  IsDBCSLeadByte(  BYTE  );  如果该字节是DBCS字符的第一个字节,则返回非0值  

 
Q  为什么要使用Unicode?  

A  

(1)  可以很容易地在不同语言之间进行数据交换。  

(2)  使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。  

(3)  提高应用程序的运行效率。  

Windows  2000是使用Unicode从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。  

Windows  CE  本身就是使用Unicode的一种操作系统,完全不支持ANSI  Windows函数  

Windows  98  只支持ANSI,只能为ANSI开发应用程序。  

Microsoft公司将COM从16位Windows转换成Win32时,公司决定需要字符串的所有COM接口方法都只能接受Unicode字符串。  

 
Q  如何编写Unicode源代码?  

A  Microsoft公司为Unicode设计了WindowsAPI,这样,可以尽量减少代码的影响。实际上,可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。只需要定义两个宏(UNICODE和_UNICODE),就可以修改然后重新编译该源文件。  

_UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常必须同时定义这两个宏。  

 
Q  Windows定义的Unicode数据类型有哪些?  

A  数据类型  说明  

WCHAR  Unicode字符  

PWSTR  指向Unicode字符串的指针  

PCWSTR  指向一个恒定的Unicode字符串的指针  

对应的ANSI数据类型为CHAR,LPSTR和LPCSTR。  

ANSI/Unicode通用数据类型为TCHAR,PTSTR,LPCTSTR。  

 
Q  如何对Unicode进行操作?  

A  字符集  特性  实例  

ANSI  操作函数以str开头  strcpy  

Unicode  操作函数以wcs开头  wcscpy  

MBCS  操作函数以_mbs开头  _mbscpy  

ANSI/Unicode  操作函数以_tcs开头  _tcscpy(C运行期库)  

ANSI/Unicode  操作函数以lstr开头  lstrcpy(Windows函数)  

所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版本函数结尾以W表示。Windows会如下定义:  

#ifdef  UNICODE  

#define  CreateWindowEx  CreateWindowExW  

#else  

#define  CreateWindowEx  CreateWindowExA  

#endif  //  !UNICODE  

 
Q  如何表示Unicode字符串常量?  

A  字符集  实例  

ANSI  “string”  

Unicode  L“string”  

ANSI/Unicode  T(“string”)或_TEXT(“string”)if(  szError[0]  ==  _TEXT(‘J’)  ){  }  

 
Q  为什么应当尽量使用操作系统函数?  
A  这将有助于稍稍提高应用程序的运行性能,因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。  

如:StrCat,StrChr,StrCmp和StrCpy等。  

 
Q  如何编写符合ANSI和Unicode的应用程序?  
A
 
(1)  将文本串视为字符数组,而不是chars数组或字节数组。  

(2)  将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。  

(3)  将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。  

(4)  将TEXT宏用于原义字符和字符串。  

(5)  执行全局性替换(例如用PTSTR替换PSTR)。  

(6)  修改字符串运算问题。例如函数通常希望在字符中传递一个缓存的大小,而不是字节。这意味着不应该传递sizeof(szBuffer),而应该传递(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters  *sizeof(TCHAR)),而不是调用malloc(nCharacters)。  
 
Q  如何对字符串进行有选择的比较?  

A  通过调用CompareString来实现。  

标志  含义  

NORM_IGNORECASE  忽略字母的大小写  

NORM_IGNOREKANATYPE  不区分平假名与片假名字符  

NORM_IGNORENONSPACE  忽略无间隔字符  

NORM_IGNORESYMBOLS  忽略符号  

NORM_IGNOREWIDTH  不区分单字节字符与作为双字节字符的同一个字符  

SORT_STRINGSORT  将标点符号作为普通符号来处理  

 
Q  如何判断一个文本文件是ANSI还是Unicode?  

A  判断如果文本文件的开头两个字节是0xFF和0xFE,那么就是Unicode,否则是ANSI。  

 
Q  如何判断一段字符串是ANSI还是Unicode?  

A  用IsTextUnicode进行判断。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此  IsTextUnicode有可能返回不正确的结果。  

 
Q  如何在Unicode与ANSI之间转换字符串?  

A  Windows函数MultiByteToWideChar用于将多字节字符串转换成宽字符串;函数WideCharToMultiByte将宽字符串转换成等价的多字节字符串。  

 
Q  如何得到汉字的Unicode编码  
A  #include  "comdef.h"  

char  *str1="你好";  

_bstr_t  str=str1;  

WCHAR  *str2=str;  

str2就是你要的UNICODE码  

 
Q  如何实现#21592#24037#36873#25321这种编码与汉字之间的转换?  

A  CString  str="#21592#24037#36873#25321";  

str+='#';  

CString  str1="";  

WCHAR  str2[5]={0,0,0,0,0};  

int  j=0;  

do  

{  

           str1=str.Left(str.Find('#',1));  

           str=str.Mid(str.Find('#',1));  

           WCHAR  i=0;  

           sscanf(str1,"#%d",&i);  

           str2[j]=i;  

           j++;  

}while(str1!="");  

_bstr_t  str3=str2;

复制搜索

复制搜索
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息