正如你发现的那样,像CRT的toupper
和Win32的CharUpper
这样的经典转换例程是相当愚蠢的。他们一般都是在全世界被认为是ASCII的时候欢呼起来的。
你需要的是一个语言敏感的转换。这是一个计算上比较昂贵的操作,但也很难正确实现10很。语言很难。所以你要尽可能地将责任转移给标准库。由于您使用的是MFC,因此很明显您的目标是Windows操作系统,这意味着您很幸运。您可以搭载微软本地化工程师的辛勤工作,并提供与外壳和其他操作系统组件一致的额外好处。
您需要调用的函数是LCMapStringEx
(或者如果您仍然针对Vista之前的平台,则为LCMapString
)。这个函数签名的复杂性充分证明了正确的语言意识字符串处理的复杂任务。
- 首先,您需要选择一个区域设置。你通常希望用户的默认语言环境,你可以用
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
进行包装。请注意0后缀,这表示这些是区域识别转换函数。它们允许你传递一个明确的语言环境,它将用于转换。
很棒的答案。今天晚些时候我会放弃它。 –