如何在 C 中正确处理非 ASCII 字符串?

ᛉᛉᛉ*_*ᛉᛉᛉ 5 c string unicode parsing

我的想法是用 C 语言编写一个类似 Hangman 的游戏。我希望它能够使用带有元音变音的德语单词(例如:\xc3\xa4, \xc3\xbc, \xc3\xb6)以及希腊单词(完全非 ASCII 字符)。

\n

我的编译器和终端可以很好地处理 Unicode。显示字符串效果很好。

\n

但是我应该如何对这些字符串进行操作呢?对于德语,我也许可以通过在函数中处理这些大小写来处理 6 个大写和小写重音字符。但考虑到希腊语,这似乎是不可能的。

\n

我写了这个测试代码。它输出字符串、字符串的长度(当然是错误的,因为 UTF-8 序列代替了两个字符)以及字符串中各个字符的纯文本和十六进制值。

\n
#include <stdio.h>\n#include <string.h>\n\nint main() {\n    printf("123456789\\n");\n    char aTestString[] = "cheese";\n    printf("%s ist %d Zeichen lang\\n", aTestString, strlen(aTestString));\n        \n    for (int i = 0; i < strlen(aTestString); i++) {\n        printf("( %c )", aTestString[i]);   // char als char\n        printf("[ %02X ]", aTestString[i]); // char in hexadezimal\n    }\n\n    printf("\\n123456789\\n");\n    char aTestString2[] = "K\xc3\xa4se";\n    printf("%s has %d characters\\n", aTestString2, strlen(aTestString2));\n        \n    for (int i = 0; i < strlen(aTestString2); i++) {\n        printf("( %c )", aTestString2[i]);  // char als char\n        printf("[ %02X ]", aTestString2[i]); // char in hexadezimal\n    }\n    \n    printf("\\n123456789\\n");    \n    char aTestString3[] = "\xce\xbb\xcf\x8c\xce\xb3\xce\xbf\xcf\x82";\n    printf("%s has %d characters\\n", aTestString3, strlen(aTestString3));\n\n    for (int i = 0; i < strlen(aTestString3); i++) {\n        printf("( %c )", aTestString3[i]);  // char als char\n        printf("[ %02X ]", aTestString3[i]); // char in hexadezimal\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

例如,推荐的方法来计算 Unicode 字符,或者查看字符串中是否存在特定的 Unicode 字符(即代码点)?我确信必须有一些简单的解决方案,因为这些字符经常在密码中使用。

\n

这是测试程序的输出:

\n
123456789\ncheese has 6 character\n( c )[ 63 ]( h )[ 68 ]( e )[ 65 ]( e )[ 65 ]( s )[ 73 ]( e )[ 65 ]\n123456789\nK\xc3\xa4se has 5 characters\n( K )[ 4B ](  )[ FFFFFFC3 ](  )[ FFFFFFA4 ]( s )[ 73 ]( e )[ 65 ]\n123456789\n\xce\xbb\xcf\x8c\xce\xb3\xce\xbf\xcf\x82 has 10 characters\n(  )[ FFFFFFCE ](  )[ FFFFFFBB ](  )[ FFFFFFCF ](  )[ FFFFFF8C ](  )[ FFFFFFCE ](  )[ FFFFFFB3 ](  )[ FFFFFFCE ](  )[ FFFFFFBF ](  )[ FFFFFFCF ](  )[ FFFFFF82 ]\n
Run Code Online (Sandbox Code Playgroud)\n

med*_*le1 5

C 的多字节字符串实用程序在这种情况下很有用。mbrlen例如,使用 来查找字符串中的字符数的一种方法(尽管这可能是我现在刚刚拼凑在一起的一种非常天真的方法)是这样的:

\n
#include <stdio.h>\n#include <wchar.h>\n#include <locale.h>\n\nsize_t string_size(const char *s)\n{\n    mbstate_t state = {0};\n    size_t len = 0;\n    for (; *s != \'\\0\'; ++len)\n    {\n        unsigned c_len;\n        for (c_len = 1; mbrlen(s+c_len-1, 1, &state) == -2; ++c_len) {}\n        s += c_len;\n    }\n    return len;\n}\n\nint main(void)\n{\n    setlocale(LC_ALL, "en_US.utf8");\n    const char *s = "z\xc3\x9f\xe6\xb0\xb4";\n    printf("%zu\\n", string_size(s));\n}\n\n// Output: 4\n
Run Code Online (Sandbox Code Playgroud)\n

使用相同的函数mbrlen,您还可以通过查找字符的长度来提取单个字符。如果您想使用多字节字符和宽字符,还有一些函数可以在多字节字符和宽字符之间进行转换。

\n