正如您所发现的,CRTtoupper
和 Win32等经典转换例程CharUpper
相当愚蠢。它们通常来自于整个世界都被认为是 ASCII 的时候。
您需要的是对语言敏感的转换。这是一个计算成本更高的操作,但也很难正确实现。语言很难。因此,如果可能的话,您希望将责任转移给标准库。由于您使用的是 MFC,因此您显然针对的是 Windows 操作系统,这意味着您很幸运。您可以借助 Microsoft 本地化工程师的辛勤工作,获得与 shell 和其他操作系统组件保持一致的额外好处。
您需要调用的函数是LCMapStringEx
(或者LCMapString
如果您仍然针对的是 pre-Vista 平台)。该函数签名的复杂性有力地证明了正确处理语言感知字符串的复杂任务。
- 首先,您需要选择一个语言环境。您通常需要用户的默认语言环境,您可以使用 指定
LOCALE_NAME_USER_DEFAULT
,但您可以在此处使用任何您想要的。
- 对于标志,您将需要
LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING
. 要执行反向操作,您可以使用LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING
. 这里还有许多其他有趣且有用的选项需要牢记。
- 然后你有一个指向源字符串的指针,以及它的字符长度(代码单元)。
- 以及一个指向接收结果的字符串缓冲区的指针,以及它的最大字符长度(代码单元)。
- 最后三个参数可以简单地设置为 NULL 或 0。
把它们放在一起:
BOOL ConvertToUppercase(std::wstring& buffer)
{
return LCMapStringEx(LOCALE_NAME_USER_DEFAULT /* or whatever locale you want */,
LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,
buffer.c_str(),
buffer.length(),
&buffer[0],
buffer.length(),
NULL,
NULL,
0);
}
请注意,我在这里对缓冲区的内容进行了就地转换,因此假设大写字符串的长度与原始输入字符串的长度完全相同。这可能是正确的,但可能不是一个普遍安全的假设,因此您要么想要添加对此类错误的处理 ( ERROR_INSUFFICIENT_BUFFER
) 和/或防御性地向缓冲区添加一些额外的填充。
如果您喜欢像现在这样使用 CRT 函数,并且它的朋友是/_totupper_l
的包装器。请注意后缀,它表示这些是区域设置感知转换函数。它们允许您传递将在转换中使用的显式语言环境。LCMapString
LCMapStringEx
_l