提问人:ᛉᛉᛉ ᛉᛉᛉ 提问时间:7/3/2023 最后编辑:tchristᛉᛉᛉ ᛉᛉᛉ 更新时间:7/3/2023 访问量:184
如何在C语言中正确处理非ASCII字符串?
How to handle non-ASCII strings properly in C?
问:
我的想法是用 C 编写一个类似 Hangman 的游戏。我希望它能够使用带有变音符号的德语单词(例如:、、)和希腊语单词(完全非 ASCII 字符)。ä
ü
ö
我的编译器和终端可以很好地处理Unicode。显示字符串效果很好。
但是我应该如何对这些字符串进行操作呢?对于德语,我也许可以通过在函数中处理这些情况来处理 6 个大写和小写重音字符。但考虑到希腊语,这似乎是不可能的。
我写了这个测试代码。它输出字符串、字符串的长度(当然是错误的,因为 UTF-8 序列代替了两个字符)以及字符串的单个字符的值(纯文本和十六进制)。
#include <stdio.h>
#include <string.h>
int main() {
printf("123456789\n");
char aTestString[] = "cheese";
printf("%s ist %d Zeichen lang\n", aTestString, strlen(aTestString));
for (int i = 0; i < strlen(aTestString); i++) {
printf("( %c )", aTestString[i]); // char als char
printf("[ %02X ]", aTestString[i]); // char in hexadezimal
}
printf("\n123456789\n");
char aTestString2[] = "Käse";
printf("%s has %d characters\n", aTestString2, strlen(aTestString2));
for (int i = 0; i < strlen(aTestString2); i++) {
printf("( %c )", aTestString2[i]); // char als char
printf("[ %02X ]", aTestString2[i]); // char in hexadezimal
}
printf("\n123456789\n");
char aTestString3[] = "λόγος";
printf("%s has %d characters\n", aTestString3, strlen(aTestString3));
for (int i = 0; i < strlen(aTestString3); i++) {
printf("( %c )", aTestString3[i]); // char als char
printf("[ %02X ]", aTestString3[i]); // char in hexadezimal
}
}
例如,计算 Unicode 字符数或查看字符串中是否包含特定 Unicode 字符(即代码点)的推荐方法是什么?我很确定一定有一些简单的解决方案,因为例如,这些字符经常用于密码中。
以下是测试程序的输出:
123456789
cheese has 6 character
( c )[ 63 ]( h )[ 68 ]( e )[ 65 ]( e )[ 65 ]( s )[ 73 ]( e )[ 65 ]
123456789
Käse has 5 characters
( K )[ 4B ]( )[ FFFFFFC3 ]( )[ FFFFFFA4 ]( s )[ 73 ]( e )[ 65 ]
123456789
λόγος has 10 characters
( )[ FFFFFFCE ]( )[ FFFFFFBB ]( )[ FFFFFFCF ]( )[ FFFFFF8C ]( )[ FFFFFFCE ]( )[ FFFFFFB3 ]( )[ FFFFFFCE ]( )[ FFFFFFBF ]( )[ FFFFFFCF ]( )[ FFFFFF82 ]
答:
5赞
mediocrevegetable1
7/3/2023
#1
在这种情况下,C 的多字节字符串实用程序很有用。例如,使用一种方法来查找字符串中的字符数(尽管我现在刚刚凑在一起的可能是一个非常幼稚的方法)是这样的:mbrlen
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
size_t string_size(const char *s)
{
mbstate_t state = {0};
size_t len = 0;
for (; *s != '\0'; ++len)
{
unsigned c_len;
for (c_len = 1; mbrlen(s+c_len-1, 1, &state) == -2; ++c_len) {}
s += c_len;
}
return len;
}
int main(void)
{
setlocale(LC_ALL, "en_US.utf8");
const char *s = "zß水🍌";
printf("%zu\n", string_size(s));
}
// Output: 4
使用相同的函数,您还可以通过查找字符的长度来提取单个字符。如果您想使用它,还可以在多字节字符和宽字符之间进行转换。mbrlen
评论
wchar_t
wchar_t