下面的代码试图解决的问题是如何有效地检测可能正在使用基于 UTF-8 的语言环境,以便在我们处理时不会查询 127 以上的所有代码点的
ctype
属性普通(非宽)字符。
至少在 macOS 14 中,当使用基于 UTF-8 的语言环境时。以下程序将显示 2 个有问题的代码点,尽管这些代码点对无符号字符有效,但它们是从不再有效的
toupper()
值得到的响应:
#include <langinfo.h>
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef WORKAROUND
static int is_utf8_locale(void)
{
const char *charmap = nl_langinfo(CODESET);
/* this shouldn't happen */
if (!charmap)
return 0;
if (!strncmp(charmap, "UTF-8", 5))
return 1;
/*
* nl_langinfo should never return an empty string, unless the "item" used is invalid, and it
* should return either the C or POSIX CODESET if the locale is missing one, but ...
*/
if (!*charmap) {
unsigned char buf[MB_CUR_MAX + 1];
return (wctomb((char *)&buf, 0xf8ff) == 3) &&
(buf[0] == 0xef && buf[1] == 0xa3 && buf[2] == 0xbf); }
return 0;
}
#endif
int main(int argc, char *argv[])
{
const char *locale = (argc > 1) ? argv[1] : "fr_FR";
int i, f = 0;
if (!setlocale(LC_CTYPE, locale))
return 127;
#ifdef WORKAROUND
if (is_utf8_locale())
return 0;
#endif
for (i = 128; i < 256; i++) {
int u, l;
unsigned char c = i;
l = tolower(c);
u = toupper(c);
if (l > 255) {
f++;
printf("%1$d: tolower(%2$d)) %2$c -> %3$d (%4$#x) %4$c\n", islower(c), c, l, l % 256);
}
if (u > 255) {
f++;
printf("%1$d: toupper(%2$d) %2$c -> %3$d (%4$#x) %4$c\n", islower(c), c, u, u % 256);
}
}
return f;
}
AFAIK,这个问题在某种程度上是最近才出现的,至少在 10.15 中不会发生,虽然
toupper()
已知“有时”会尝试提供更多帮助(作为 BSD 扩展),但我在我最近尝试过的任何 BSD 系统,他们都提到这种行为已被弃用。
“-DWORKAROUND”可以工作,但恕我直言,它太丑陋了,而且在线程环境中也会出现问题,而且由于 macOS 定义其语言环境的方式,特别容易受到攻击。
所有没有明确
.${CHARMAP}
的语言环境都会显示来自 nl_langinfo()
的有问题的响应,以及包含 .UTF-8
以及有时在其他系统中使用 .utf8
的语言环境(尽管它们总是从 nl_langinfo()
返回正确的值)这些情况)。
该解决方法显然需要针对非 POSIX 系统的额外代码。
受影响的应用程序不支持 UTF-8 以外的外来多字节编码,但使用
wctomb()
的检测很脆弱,可能无法在 Apple 系统之外工作,因此也欢迎建议或测试结果。
如何在最近使用 UTF-8 语言环境的 macOS 中处理 toupper() 返回的大于 255 的值
在任何语言环境和任何系统中,都无法使用
toupper
(在具有正常 8 位字符的健全系统上)处理大于 255 的值。