将字符转换为阿拉伯语中的大写
Converting characters to uppercase in Arabic
我有将字母转换为大写的代码:
// make this character upper
if(_istalpha(zChar) && !_istupper(zChar))
pMsg->wParam = (WPARAM)_toupper(zChar);
它已经工作了很多年。最近我被要求支持阿拉伯语,我的用户说字母被损坏了。就是因为上面的代码。
有人用阿拉伯语告诉我大写字母不适用。我知道我可以测试我的程序设置以查看它们是否使用阿拉伯语并避免使用此代码。但是还有别的办法吗?
我知道你先打电话给 _tsetlocale
的日期。
更新:
找到关于 toupper 的主题,其中提到了语言环境设置!会试试的。
如您所见,像 CRT 的 toupper
和 Win32 的 CharUpper
这样的经典转换例程相当愚蠢。他们通常来自于全世界都被认为是 ASCII 的时代。
您需要的是语言敏感的转换。这是一个计算成本更高的操作,而且 非常 难以正确实施。语言很难。因此,如果可能的话,您想将责任卸载到标准库。由于您使用的是 MFC,您显然是针对 Windows 操作系统,这意味着您很幸运。您可以借助 Microsoft 本地化工程师的辛勤工作,获得与 shell 和其他 OS 组件保持一致的额外好处。
如果您仍然针对 Vista 之前的平台,则需要调用的函数是 LCMapStringEx
(or 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
) and/or 防御性地添加一些缓冲区的额外填充。
如果您更喜欢像现在这样使用 CRT 函数,_totupper_l
及其朋友是 LCMapString
/LCMapStringEx
的包装器。请注意 _l
后缀,它表示这些是区域设置感知转换函数。它们允许您传递将在转换中使用的显式语言环境。
我假设您使用的是 UTF-8 字符串。在这种情况下,您的代码需要支持 UTF-8,即能够处理多字节字符。例如,如果双字节字符串中的第二个字符恰好与字母 'c' 的值相同,您的代码将选取它并将其转换为大写,从而产生完全不同的双字节字符。
看看这个问题:
Convert a unicode String In C++ To Upper Case
我有将字母转换为大写的代码:
// make this character upper
if(_istalpha(zChar) && !_istupper(zChar))
pMsg->wParam = (WPARAM)_toupper(zChar);
它已经工作了很多年。最近我被要求支持阿拉伯语,我的用户说字母被损坏了。就是因为上面的代码。
有人用阿拉伯语告诉我大写字母不适用。我知道我可以测试我的程序设置以查看它们是否使用阿拉伯语并避免使用此代码。但是还有别的办法吗?
我知道你先打电话给 _tsetlocale
的日期。
更新:
找到关于 toupper 的主题,其中提到了语言环境设置!会试试的。
如您所见,像 CRT 的 toupper
和 Win32 的 CharUpper
这样的经典转换例程相当愚蠢。他们通常来自于全世界都被认为是 ASCII 的时代。
您需要的是语言敏感的转换。这是一个计算成本更高的操作,而且 非常 难以正确实施。语言很难。因此,如果可能的话,您想将责任卸载到标准库。由于您使用的是 MFC,您显然是针对 Windows 操作系统,这意味着您很幸运。您可以借助 Microsoft 本地化工程师的辛勤工作,获得与 shell 和其他 OS 组件保持一致的额外好处。
如果您仍然针对 Vista 之前的平台,则需要调用的函数是 LCMapStringEx
(or 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
) and/or 防御性地添加一些缓冲区的额外填充。
如果您更喜欢像现在这样使用 CRT 函数,_totupper_l
及其朋友是 LCMapString
/LCMapStringEx
的包装器。请注意 _l
后缀,它表示这些是区域设置感知转换函数。它们允许您传递将在转换中使用的显式语言环境。
我假设您使用的是 UTF-8 字符串。在这种情况下,您的代码需要支持 UTF-8,即能够处理多字节字符。例如,如果双字节字符串中的第二个字符恰好与字母 'c' 的值相同,您的代码将选取它并将其转换为大写,从而产生完全不同的双字节字符。 看看这个问题: Convert a unicode String In C++ To Upper Case