Alter Mann's accepted answer基本正确,但不应该只是硬编码一个自定义函数来计算多字节字符串中未编码为可见字符的字节数:您应该使用setlocale(LC_ALL, "")
或类似方法来本地化代码,并使用strlen(str) - mbstowcs(NULL, str, 0)
来计算字符串中未编码为可见字符的字节数。
setlocale()
是标准C(C89、C99、C11)中的一部分,也在POSIX.1中定义。mbstowcs()
是标准C99和C11中的一部分,并且也在POSIX.1中定义。两者都在Microsoft C库中实现,因此基本上可以在任何地方使用。
考虑以下示例程序,它打印在命令行上指定的C字符串:
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <stdio.h>
static size_t ms_len(const char *const ms)
{
if (ms)
return mbstowcs(NULL, ms, 0);
else
return 0;
}
static size_t ms_extras(const char *const ms)
{
if (ms)
return strlen(ms) - mbstowcs(NULL, ms, 0);
else
return 0;
}
int main(int argc, char *argv[])
{
int arg;
setlocale(LC_ALL, "");
for (arg = 1; arg < argc; arg++)
printf(">%-*s< (%zu bytes; %zu chars; %zu bytes extra in wide chars)\n",
(int)(10 + ms_extras(argv[arg])), argv[arg],
strlen(argv[arg]), ms_len(argv[arg]), ms_extras(argv[arg]));
return EXIT_SUCCESS;
}
如果您将上述内容编译为
example
,并运行。
./example aaa aaä aää äää aa€ a€€ €€€ a ä €
该程序将输出
>aaa < (3 bytes; 3 chars; 0 bytes extra in wide chars)
>aaä < (4 bytes; 3 chars; 1 bytes extra in wide chars)
>aää < (5 bytes; 3 chars; 2 bytes extra in wide chars)
>äää < (6 bytes; 3 chars; 3 bytes extra in wide chars)
>aa€ < (5 bytes; 3 chars; 2 bytes extra in wide chars)
>a€€ < (7 bytes; 3 chars; 4 bytes extra in wide chars)
>€€€ < (9 bytes; 3 chars; 6 bytes extra in wide chars)
>a < (1 bytes; 1 chars; 0 bytes extra in wide chars)
>ä < (2 bytes; 1 chars; 1 bytes extra in wide chars)
>€ < (3 bytes; 1 chars; 2 bytes extra in wide chars)
> < (4 bytes; 1 chars; 3 bytes extra in wide chars)
如果最后一个
<
与其他字符不对齐,那是因为所使用的字体不是固定宽度:表情符号
比普通字符如
Ä
更宽。这就是全部原因。怪字体吧。
最后一个字符是U+1F608带角笑脸,来自
Emoticons unicode block,如果您的操作系统/浏览器/字体无法显示它。在Linux中,我拥有的所有终端(包括控制台(非图形系统控制台))中,上述所有
>
和
<
都正确对齐,尽管控制台字体没有表情符号的字形,而只是显示成了菱形。
与
Alter Mann's answer不同,这种方法是可移植的,并且不假设当前用户实际使用的字符集是什么。
printf
可能不支持UTF-8。 - user694733