代码升级:从多字节到Unicode字符集

    十几年前,还是用VC++6.0开发,使用的是多字节字符集,字符串类型的变量一般用:char[], char*,const char*,CString。随着开发工具的更新,需求的变化,更高版本的系统需要使用Unicode字符集。旧代码的算法逻辑并没有什么问题,只是字符串参数类型和一些字符串操作函数需要修改一下,当然不必重写一遍,只需要对代码进行升级,从多字节字符第一步集升级到Unicode字符集。这里就讲一下如何快速升级字符串。

1、修改常量字符串

    这个操作的目的是将"......."替换为_T("......"),这里_T()是一个宏定义,在多字节字符集下什么都不做,在Unicode字符集下则在字符串前面加一个“L”字符,标识字符串为Unicode字符集。一般来说,字符串内容在代码里是非常多的,如果遍历所有文件去手工修改,这个工作量无疑是非常大的,但我们完全不需要这么做。打开一个代码文件,打开“在文件中替换”对话框(快捷键:Ctrl+Shit+H),展开“查找选项”,勾选“使用正则表达式”,然后你会看到“查找内容”和“替换为”下方的输入框右边分别有个按钮(按钮文字为"(a)+")被激活。
    点击“查找内容”这个按钮,就会出现一个菜单,各个菜单项就是预定义的一些正则表达式及其用途说明,最后一项是正则表达式说明。这次,我们要使用的是菜单“引用字符串”,表达式为:((\".+?\")|('.+?'))。这个表达式匹配用引号或单引号包含的任意一个或多个字符。我们需要处理的字符串只用引号,而且还包含""这种引号内不含字符的形式,需要修改为:(\".*?\") 。就是将“.+”换成“.*”,去掉外面的括号和“|”后面的部分,“.+”和“.*”这两种表达式也可以从按钮菜单上看到其说明。
    点击“替换为”对应的按钮,弹出的菜单比较简单,因为我们只是要在原字符外面使用“_T()”,所以使用“$1”就好,这个表达式就代表匹配的字符串,任何非正则表达式的部分,会被直接原样替换到所搜匹配的项。
   总结一下,就是在“查找内容”的输入框输入:(\".*?\"),在“替换为”的输入框输入:_T($1),查找范围选择“整个解决方案”,为了检验一下效果,可以点击“查找下一个”按钮,看一下选中的匹配项是否正确,然后点击“替换”查看一下替换的结果是否正确,如果无误,撤销刚才的替换操作,点击“全部替换”,等待操作完成,在查找结果窗口可以看到替换结果。

2、特殊字符串处理

   按照操作1处理之后,你会发现有些不需要处理的地方也被处理了,一类是头文件包含语句,例如:include "StdAfx.h",一类是已经是Unicode形式的字符串,例如:L"..",_T(""),这些字符串被替换后需要恢复。同样,我们也可以使用正则表达式替换,具体如下:

    将 #include _T("...") 还原为 #include "...",查找内容:#include _T\((\".*?\")\),替换为:#include $1
    将 _T(_T("...")) 还原为 _T("..."),查找内容:_T\((_T\(\".*?\"\))\),替换为:$1
    L_T("...") 还原为 L"...",查找内容:L_T\((\".*?\")\),替换为:L$1
    当然,还有其他情况可以自动处理或手工处理,比如 extern "C" ,代码不会很多,手工处理一下就行了。

3、字符串函数处理

    一些字符串函数,其实本身已经针对多字节字符版和Unicode字符版实现了两个版本,函数定义的头文件里已经用宏形式进行了自动替换,旧代码里是直接使用了多字节字符版本,只需换成宏形式的函数名,这样就可以兼容多字节字符和Unicode字符两个版本了。常见的函数替换如下,这里就不需要使用正则表达式替换,直接替换即可:
atoi -> _tstoi
atol -> _tstol
atof -> _tstof
strlen -> _tcslen
strcpy -> _tcscpy
strcat -> _ tcscat
sscanf -> _stscanf
sprintf -> _stprintf

4、char 类型处理

    一般情况下, char 类型需要替换为 TCHAR。 TCHAR 也是一个宏定义形式,在多字节字符集下是 char,在Unicode字符集下是wchar_t。除了直接写为 char 的形式,还有LPSTR和LPCSTR两种宏定义形式,展开宏结果为char*和const char*,这两个也需要替换,分别是 LPTSTR 和 LPCTSTR 这两个宏,展开是 TCHAR* 和 const TCHAR*。

5、CString 类型处理

    CString 本身是自动适应字符集的。编译的时候,你可能会发现这种形式 CString str = "..."; 是可以正常编译的,实际上这是因为CString实现了参数为多字节字符串的构造函数,函数里自动进行了字符集转换,相当于 CStirng str = CString("...");,虽然这种形式可以正常使用,但增加了不必要的转换操作。实际上,这种情况是可以让编译器识别出来的,需要在头文件定义一个宏:
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
意思是某些 CString 构造函数将是显式的,这样 CString str = "...";将不能自动转换为 CStirng str = CString("...");形式,由于CString并不实现参数为多字节字符串的=操作,编译器会产生编译错误。于是,这样就可以发现非Unicode字符串然后修改为 CStirng str = _T("...")。

6、多字节字符集与Unicode字符集的转换

    这种转换函数当然已经存在,就是 MultiByteToWideChar 和 WideCharToMultiByte 这两个函数,如果觉得处理参数和返回值是有点麻烦,可以自己封装一下。
    实际上还有偷懒的方法,例如,要转换为多字节字符集,可以使用 CStringA 这个类型,这个类型是使用多字节字符集的,实现了使用Unicode字符串做参数的构造函数,也就是内部自动转换的。于是可以在需要转换的地方这样做:CStringA(unicode),在需要const char*的地方使用 (const char*)CStringA(unicode) 这样处理。反之亦然。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值