我有这个代码将字母转换为大写:
// make this character upper
if(_istalpha(zChar) && !_istupper(zChar))
pMsg->wParam = (WPARAM)_toupper(zChar);
它已经工作多年了。最近我被要求支持阿拉伯语,我的用户说信件已被破坏。这是因为上面的代码。
我用阿拉伯语告诉我,大写不适用。我知道我可以测试我的程序设置,看看他们是否使用阿拉伯语并避免使用此代码。但还有另一种方式吗?
我知道你的日期首先叫_tsetlocale
。
更新
找到关于提及区域设置的toupper的主题!会尝试一下。
答案 0 :(得分:2)
正如您所发现的那样,CRT的toupper
和Win32的CharUpper
之类的经典转换例程相当愚蠢。它们通常都是从假设全世界都是ASCII的时候开始的。
您需要的是语言敏感的转化。这是一种计算上更昂贵的操作,但非常难以正确实现。语言很难。因此,如果可能的话,您希望将责任卸载到标准库中。由于您使用的是MFC,因此您明显瞄准了Windows操作系统,这意味着您很幸运。您可以依靠Microsoft的本地化工程师的辛勤工作,提供与shell和其他操作系统组件的一致性的额外好处。
您需要呼叫的功能是LCMapStringEx
(如果您仍然定位到Vista之前的平台,则需要LCMapString
)。这个函数的签名的复杂性充分证明了正确的语言识别字符串处理的复杂任务。
LOCALE_NAME_USER_DEFAULT
指定,但您可以在此处使用任何内容。LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING
。要执行相反操作,请使用LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING
。这里还有很多其他有趣且有用的选项,请记住。全部放在一起:
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
后缀,表示这些是区域设置感知转换函数。它们允许您传递显式区域设置,该区域设置将在转换中使用。
答案 1 :(得分:0)
我假设你使用的是UTF-8字符串。在这种情况下,您的代码需要知道UTF-8,即能够考虑多字节字符。例如,如果双字节字符串中的第二个字符恰好与字母“c”相同,则它将被您的代码拾取并转换为大写,从而产生完全不同的双字节字符。 看看这个问题: Convert a unicode String In C++ To Upper Case