在阿拉伯语中将字符转换为大写

时间:2016-12-03 08:19:32

标签: visual-studio-2015 mfc arabic toupper

我有这个代码将字母转换为大写:

// make this character upper
if(_istalpha(zChar) && !_istupper(zChar))
   pMsg->wParam = (WPARAM)_toupper(zChar);

它已经工作多年了。最近我被要求支持阿拉伯语,我的用户说信件已被破坏。这是因为上面的代码。

我用阿拉伯语告诉我,大写不适用。我知道我可以测试我的程序设置,看看他们是否使用阿拉伯语并避免使用此代码。但还有另一种方式吗?

我知道你的日期首先叫_tsetlocale

更新

找到关于提及区域设置的toupper的主题!会尝试一下。

2 个答案:

答案 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。这里还有很多其他有趣且有用的选项,请记住。
  • 然后你有一个指向源字符串的指针,以及它的字符长度(代码单位)。
  • 指向接收结果的字符串缓冲区的指针,以及字符的最大长度(代码单位)。
  • 最后三个参数可以简单地设置为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后缀,表示这些是区域设置感知转换函数。它们允许您传递显式区域设置,该区域设置将在转换​​中使用。

答案 1 :(得分:0)

我假设你使用的是UTF-8字符串。在这种情况下,您的代码需要知道UTF-8,即能够考虑多字节字符。例如,如果双字节字符串中的第二个字符恰好与字母“c”相同,则它将被您的代码拾取并转换为大写,从而产生完全不同的双字节字符。 看看这个问题: Convert a unicode String In C++ To Upper Case