2016-12-03 88 views
2

我有这样的代码字母转换为大写:将字符转换为大写阿拉伯文

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

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

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

我知道你的日期,你首先打电话给_tsetlocale

更新:

位于此话题有关toupper其中提到区域设置!将尝试它。

回答

2

正如你发现的那样,像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​​后缀,这表示这些是区域识别转换函数。它们允许你传递一个明确的语言环境,它将用于转换。

+0

很棒的答案。今天晚些时候我会放弃它。 –

0

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