65.9K
CodeProject 正在变化。 阅读更多。
Home

自动为带引号的字符串添加 _T 宏以及其他多字节-Unicode 转换

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.44/5 (9投票s)

2009 年 10 月 14 日

CPOL

3分钟阅读

viewsIcon

36624

在VC++中移植到Unicode配置时,为引用的字符串添加_T宏。

引言

本文将介绍如何将Visual Studio C++项目从多字节配置移植到Unicode,并特别强调

  1. 自动为引用的字符串添加_T("")宏。
  2. std::stringstd::ostringstreamstd::ofstream移植到兼容Unicode的版本。
  3. std::string中存储Unicode值。

背景

很久以前,我开始了一个Visual Studio 6 C++项目,我写的第一行代码是

AfxMessageBox("Hello World!");

当我点击“构建”时,直到我将项目配置从默认的Unicode更改为多字节,它才能编译。

从那一刻起,我就知道我最好在每个字符串前面加上_T宏,但过了一段时间,我停止这样做了。

一年后,当项目变成一个20万行代码的庞然大物时,我被要求将程序翻译成其他语言,如俄语和中文。将项目配置改回Unicode后,出现了成千上万的错误,主要是因为引用的文本没有添加_T宏。

本文将介绍如何使用Visual Studio的宏资源管理器,自动为引用的字符串添加_T("")宏。

自动为引用的字符串添加_T("")宏

使用代码

  1. 在Visual Studio中打开你的项目。
  2. 在顶部主菜单中,选择“工具 -> 宏 -> 宏资源管理器”。宏资源管理器面板应该会出现在屏幕的右侧。
  3. 右键单击“MyMacros”并选择“新建模块”。
  4. 精确地输入以下名称:“AutoT”。
  5. 右键单击新创建的模块并选择“编辑”。
  6. 将以下文本粘贴进去,覆盖自动生成的代码中已有的几行。
  7. 保存并关闭宏。

请注意,尽管以下代码是用VBScript编写的,但它是为C++程序设计的。

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module AutoT

    Sub ReplaceXWithY(ByVal X As String, ByVal Y As String, _
                      Optional ByVal MatchCase As Boolean = False, _
                      Optional ByVal PatternSyntax As _
                        EnvDTE.vsFindPatternSyntax = _
                        vsFindPatternSyntax.vsFindPatternSyntaxLiteral)

        DTE.Find.Action = vsFindAction.vsFindActionReplace
        DTE.Find.FindWhat = X
        DTE.Find.ReplaceWith = Y
        DTE.Find.Target = vsFindTarget.vsFindTargetOpenDocuments
        DTE.Find.MatchCase = MatchCase
        DTE.Find.MatchWholeWord = False
        DTE.Find.Backwards = False
        DTE.Find.MatchInHiddenText = False
        DTE.Find.PatternSyntax = PatternSyntax

        If (DTE.Find.Execute() = vsFindResult.vsFindResultNotFound) Then
            Throw New System.Exception("vsFindResultNotFound")
        End If

    End Sub

    Sub QuotedTextTo_T()
        ReplaceXWithY("{:q}", "_T(\1)", True, _
                      vsFindPatternSyntax.vsFindPatternSyntaxRegExpr)
    End Sub

End Module

当你回到你的项目时,你会在右侧的宏资源管理器面板中看到一个名为“AutoT”的宏。

每次双击该宏时,它将标记当前打开的C++文件中下一个引用的文本。再点击一次宏,它就会用_T宏包装文本。

AfxMessageBox("Hello World!");

将被改为

AfxMessageBox(_T("Hello World!"));

并可以在多字节和Unicode配置中进行编译!

建议为宏添加键盘快捷键

  1. 在Visual Studio的顶部主菜单中,选择“工具 -> 选项”
  2. 点击左侧“环境”旁边的+号
  3. 点击“键盘”
  4. 在右侧窗格中,在“显示包含命令的:”编辑框中键入“AutoT”,以找到我们新的宏。
  5. 点击宏,并为其分配一个快捷键(我选择了Ctrl-Alt-Num0)。
  6. 单击“确定”

现在,每次按下该键盘组合时,宏就会被执行。

请注意:不要被诱惑而盲目地让脚本完成所有工作。需要人工验证。脚本会尝试将_T宏添加到像这样的行中

#include "StdAfx.h"

为了让脚本跳过这样的行,只需按键盘上的“右”箭头键。

该脚本也不够智能,无法识别文本中的引号,比如

AfxMessageBox(_T("Hello \"World!\" "));

它也无法跳过已经被_T宏包装的引用的文本,但好消息是它永远不会跳过一个引用的文本:)

请注意,您还必须将所有类似strcmp的出现重命名为TCHAR.H例程,如_tcscmp

将std::string、std::ostringstream、std::ofstream移植到兼容Unicode的版本

如果在你的多字节项目中广泛使用了std::stringstd::ostringstreamstd::ofstream,这些在Unicode编译中表现不佳。

最简单的方法是定义以下内容,并将你的程序中所有std::string的出现重命名为tstring,例如。

#include <string>

typedef std::basic_string<TCHAR> tstring;
typedef std::basic_ostringstream<TCHAR> tostringstream;
typedef std::basic_ofstream<TCHAR> tofstream;

此外,将代码中的所有char替换为TCHAR

在std::string中存储Unicode值

要存储Unicode值,可以使用std::wstring,但当必须将Unicode值存储在标准的std::string或char数组中时,可以将其存储为UTF-8格式,TinyXML等也使用了这种格式。

以下辅助函数可能有助于您进行转换

std::string CStringToString(const CString& cs)
{
    // Convert a TCHAR string to a LPCSTR
    CT2CA pszConvertedAnsiString (cs);

    // construct a std::string using the LPCSTR input
    //std::string strStd (pszConvertedAnsiString);
    return pszConvertedAnsiString; 
}

tstring CStringTo_tstring(const CString& cs)
{
    std::basic_string <TCHAR> bsConverted (cs);
    return bsConverted;
}

std::string tstringTo_stdString(const tstring& ts)
{
    return CStringToString(ts.c_str()).c_str();
}

tstring UTF8charTo_tstring( const char* strIn )
{
    wchar_t buffer[2048];//!!H
    MultiByteToWideChar(CP_UTF8, 0, strIn, -1, buffer, 2048 );//!!H
    tstring ts1 = CString(buffer);
    return ts1;
}

std::string tstringToUTF8string( tstring tsIn )
{
    char buffer[2048];//!!H
    WideCharToMultiByte( CP_UTF8, 0, tsIn.c_str() , -1, buffer, 2048, NULL, NULL );
    std::string s1 = buffer;
    return s1;
}

bool HasUnicodeChars( tstring tsIn )
{
    std::string sNarrow = tstringTo_stdString(tsIn);
    tstring tsFromNarrow = CString(sNarrow.c_str());

    if ( tsFromNarrow != tsIn )
        return true;
    else
        return false;
}

tstring转换为char*

CStringToString(sName.c_str()).c_str()

std::string转换为tstring

tstring ts30 = CString(stdS1.c_str());

注意:UTF-8字符串类似于char字符串,但Unicode字母可能需要两个字符,使字符串变长。

tstring ts1;
ts1 = _T("Some foreign language text");
int nLen = ts1.length();
int nSize = ts1.size();
    
//Convert wide string to std string
std::string s2 = tstringToUTF8string(ts1);
int nLen2 = s2.length();
int nSize2 = s2.size();
    
//Convert std string back to wide string
tstring ts5 = UTF8charTo_tstring(s2.c_str());
© . All rights reserved.