使用 UNICODE 和 ANSI 的混合编程

 1,VS2010 编译器的菜单上 “项目----属性---左侧的配置属性----常规---右侧的 字符集 可以对项目所要使用的字符集进行定义,可以选择”使用Unicode字符集“、“使用多字节字符集”等等。

 

2MessageBox 有三个版本:MessageBoxA, MessageBoxW, MessageBox;

 

****************************************

WINUSERAPI

int

WINAPI

MessageBoxA(

    __in_opt HWND hWnd,

    __in_opt LPCSTR lpText,

    __in_opt LPCSTR lpCaption,

    __in UINT uType);

WINUSERAPI

int

WINAPI

MessageBoxW(

    __in_opt HWND hWnd,

    __in_opt LPCWSTR lpText,

    __in_opt LPCWSTR lpCaption,

    __in UINT uType);

#ifdef UNICODE

#define MessageBox  MessageBoxW

#else

#define MessageBox  MessageBoxA

#endif // !UNICODE

 

**********************************************

即:如果项目设置使用UNICODE字符集, MessageBox 就相当于 MessageBoxW, 否则 MessageBox 就相当于 MessageBoxA;

 

MessageBoxA函数的第二和第三个参数的类型都是LPCSTR ,它是什么呢?

typedef __nullterminated CONST CHAR *LPCSTR, *PCSTR;

它是 CONST CHAR CONST CHAR 是什么?

 

#ifndef CONST

#define CONST               const

#endif

 

typedef char CHAR;

 

所以 CONST CHAR 就相当于 const char; 所以MessageBoxA 中的第二和第三个参数要是多字节(ANSI)类型常量的。

 

MessageBoxW函数的第二和第三个参数的类型都是LPCWSTR ,它是什么呢?

typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;

它是 CONST WCHAR; CONST WCHAR又是什么?

#ifndef CONST

#define CONST               const

#endif

 

#ifndef _MAC

typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character

#else

// some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char

typedef unsigned short WCHAR;    // wc,   16-bit UNICODE character

#endif

 

所以CONST WCHAR 就相当于 const wchar_t ,所以MessageBoxW 中的第二和第三个参数要是16位的UNICODE 常量。

 

3CString 也有三个版本,CStringA, CStringW, CString;

 

**************************************************

 

typedef ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > > CStringW;

typedef ATL::CStringT< char, StrTraitMFC_DLL< char > > CStringA;

typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;

 

******************************************************************

4,上面CString 模板中的 TCHAR 是什么?

 

*****************************************************************

//

// Neutral ANSI/UNICODE types and macros

//

#ifdef  UNICODE                     // r_winnt

 

#ifndef _TCHAR_DEFINED

typedef WCHAR TCHAR, *PTCHAR;

typedef WCHAR TBYTE , *PTBYTE ;

#define _TCHAR_DEFINED

#endif /* !_TCHAR_DEFINED */

 

/*........(此处省略多条定义)*/

 

#else   /* UNICODE */               // r_winnt

 

#ifndef _TCHAR_DEFINED

typedef char TCHAR, *PTCHAR;

typedef unsigned char TBYTE , *PTBYTE ;

#define _TCHAR_DEFINED

#endif /* !_TCHAR_DEFINED */

 

 

 

即:如果项目设置使用UNICODE字符集 ,TCHAR 就相当于 WCHAR,也就是wchar_t;否则 TCHAR 就相当于 char;所以项目设置使用UNICODE字符集, CString就相当于CStringW, 否则CString 就相当于CStringA.

 

如果在配置中设置了使用UNICODE字符集,那么CString 的作用就如同CStringW一样,如果把光标移动到程序中的CString上面,就会显示它的第一个模板参数是wchar_t。这时如果修改字符集使用多字节字符,CString的作用就如同CStringA一样了,如果把光标移动到它上面,会显示它的第一个模板参数是char

 

5 在给宽字节变量赋值时,可以在值前加“L”,也可以加“_T”,比如:

   wstring x(L"你好");

   CStringW y(L"再见");

 

   wstring x(_T("你好") );

   CStringW y(_T("再见") );

 

   在值前加“L”是常见用法,那么“_T”表示什么呢?

#define _T(x)       __T(x)

#define _TEXT(x)    __T(x)

 

那么 __T(x) 是什么?

 

#ifdef  UNICODE                     // r_winnt

/*........(此处省略多条定义)*/

#define __TEXT(quote) L##quote      // r_winnt

#else   /* UNICODE */               // r_winnt

/*........(此处省略多条定义)*/

#define __TEXT(quote) quote         // r_winnt

#endif /* UNICODE */                // r_winnt

 

即:如果项目设置使用UNICODE字符集, _T 就相当于“L”,否则加“_T”就如同没加。

 

6  ANSI UNICODE 的混合编程。编程时,使用ANSI节省存储空间,但遇到处理中文时很不方便。如何使所编写的一个程序在处理英文时,使用ANSI字符集,在处理中文时,使用UNICODE字符集,并且不需要修改大量代码。

 a, 使用CString 类型的字符串变量;

 b, 使用MessageBox 来弹出消息;

 c, 使用TCHAR类型的字符变量;

 d, 使用_T来表示宽字节字符。

 

    在项目设置使用UNICODE字符集时,CString 就相当于CStringW, MessageBox就相当于MessageBoxWTCHAR 就相当于wchar_t _T就相当于L

   在项目设置使用多字节字符集时,CString 就相当于CStringA, MessageBox就相当于MessageBoxATCHAR就相当于char _T就相当于不存在。

 

比如一条语句:

CString  x( _T("大家好") );

在项目设置使用UNICODE字符集时,CString 就相当于 CStringW, x 中存储的字符长度为3_T就相当于L;在项目设置使用多字节字符集时,CString 就相当于CStringA, x 中存储的字符长度为6

 

 

string wstring 却没有类似的转化功能。

 

typedef basic_string<char, char_traits<char>, allocator<char> > string;

typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring

 

 

当然如果处于某种考虑,某个变量就要存储 宽字节字符 ,而不是存储ANSI字符,就可以显式的使用CStringW类型,而不是使用CString

 

 

 

 

二、分析一个文本断句的函数CStringW的函数和正则表达式实现文本断句

 

文本断句函数是在文本信息处理中经常用到,并且如果对这个函数做适当的修改就可以用于文本块的切割。

 

我以前编写过一个这样的函数,在ANSI字符集下编程,

 

   为了判断一个字符中文标点和英文标点,定义了char类型的变量来存储一个字节,但是这要会出现一个问题:在某些实现中char 会被当作signed类型,在另外一些实现中被当作 unsigned 类型,因此在不同的编译器中需要修改代码。比如,在我用的VC6.0中,判断一个字节是不是英文标点用 if(a>0),而到了vc2010,就要用if(a<129)。另外在ANSI字符集下编程断句还容易出现字符错位问题。

 

最近又编写了一个文本断句函数,使用UNICODE字符集,用较少的代码,实现了功能:

 

///

//function: cut sentence to blocks;

//input: csLine, mark;

//output:csLine after cut;

void cutSentenceAtUnicode( CStringW& csLine, const CStringW mark )

{

       for( int i = 0; i < ( csLine.GetLength() - 1 ); ++i )

              if (  ( ( csLine.Mid(i,1) ).FindOneOf( mark ) >= 0 ) &&

                    ( ( csLine.Mid( i + 1 ,1) ).FindOneOf( mark ) < 0 )  )

                     csLine.Insert(i+1, _T("\n") );

 

       csLine = csLine + L"\n";

 

}

 

注释: csLine 是需要断句的字符串, mark是切分的标志,比如可以定义为:

CStringW mark(L".?!\"。,?!”")

可以同时在里面包含中文标点和英文标点,以及句末标点和右匹配标点。都会把它当作宽字符来处理。

 

思路很简单,就是:如果字符串的第i处字符包含在切分标志中,而第i+1处字符并不包含在切分标志中,就在第i处之后添加一个回车符。

 

这个函数可以处理UNICODE字符,当然也可以把ANSI的转化为UNICODE来断句。

 

// 用正则表达式来断句 (输入和输出均为 CStringW类型)

void cutSentenceAtUnicodeReg( CStringW& csLine )

{

      

  wregex reg( _T("([.?!\"。,?!”])(?![ .?!\"。,?!”])") );

  wstring wstr = csLine;

  wstring wfmt(_T("$1\n"));

  csLine = ( regex_replace(wstr, reg, wfmt)).c_str();      

}

 

 

// 用正则表达式来断句 (输入和输出均为 wstring 类型)

void cutSentenceAtUnicodeReg( wstring& csLine )

{

      

  wregex reg( _T("([.?!\"。,?!”])(?![ .?!\"。,?!”])") );

  wstring wfmt(_T("$1\n"));

  csLine =  regex_replace(csLine, reg, wfmt) ;

}

 

正则表达式“([.?!\"。,?!”])(?![ .?!\"。,?!”])”有两个组,第一组是“([.?!\"。,?!”])”、第二组是“(?![.?!\"。,?!”])”,与第一组匹配的字符串会被保存到缓冲区1中,第二组的作用是“否定式向前查找”,它的模式是(?!...);  就是当在第一组之后,没有出现第二组中的内容才符合匹配的条件;如果在第一组后出现了第二组的内容就不符合匹配的条件。所以这个表达式所表达的思想与第一种文本切分的方法是一致的,即:如果字符串的第i处字符包含在切分标志中,而第i+1处字符并不包含在切分标志中,就在第i处之后添加一个回车符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值