C - 使用特殊字符格式化字符串大小

chr*_*s13 5 c string format special-characters

所以,我试图从字符串格式良好的比赛中打印灯具,但我发现只要有'é''í''á'这样的特殊字符,即使我指定了最大值,也会打印+1大小长度.

代码在哪里:

printf("=> %-25s (%d) vs (%d) \t%-25s\n", f->home_team_name, f->goals_home_team, f->goals_away_team, f->away_team_name);
Run Code Online (Sandbox Code Playgroud)

对于具有这些字符的团队,输出如下:

=> Palmeiras               (2) vs (0)   Botafogo               
=> Atlético Mineiro       (4) vs (3)    Grémio                
=> Atlético PR            (3) vs (0)    Palmeiras              
=> Botafogo                (2) vs (2)   Cruzeiro   
Run Code Online (Sandbox Code Playgroud)

但我希望输出看起来像,即使使用特殊字符:

=> Tottenham Hotspur FC    (0) vs (0)   Leicester City FC      
=> West Ham United FC      (0) vs (0)   Everton FC             
=> Burnley FC              (0) vs (0)   AFC Bournemouth   
Run Code Online (Sandbox Code Playgroud)

我试图寻找格式化标志但无法找到解决方案.

Grz*_*ski 3

中的格式字符串printf不考虑多字节字符。

\n\n

一种可能的解决方案是通过函数对字符串的宽字符进行计数mbstowcs。然后从所检查字符串的长度(即以字节为单位)中减去获得的计数。这会产生一个(非负)“补偿值”,可以将其添加到printf\ 的格式字段宽度中。

\n\n

mbstowcs函数描述为:

\n\n
\n

将多字节字符串从第一个\n 元素指向 的数组转换为其src宽字符表示形式。\n 转换后的字符存储在\n 指向的数组的连续元素中dstlen写入目标数组的字符数不超过宽字符。

\n
\n\n

在您的情况下,这意味着 UTF-8 编码的八位字节(在 数组中表示char)被转换为某种宽表示形式,这保证了任何多字节字符(最多特定于区域设置的MB_CUR_MAX字节)都可以由不超过一个对象进行编码wchar_t

\n\n

C11 标准的相关引用包含在 7.19/2通用定义<stddef.h>中:

\n\n
\n

wchar_t

\n\n

它是一个整数类型,其值范围可以表示支持的语言环境中指定的最大扩展字符集的所有成员的不同代码;

\n
\n\n

例如,在 Linux 平台上,宽字符最有可能以UCS-4(称为 UTF-32)表示。

\n\n

这是一个概念证明:

\n\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <locale.h>\n\nstatic inline size_t widestrlen(const char *str)\n{\n    return mbstowcs(NULL, str, strlen(str));\n}\n\nstatic inline size_t compensation(const char *str)\n{\n    return strlen(str) - widestrlen(str);\n}\n\nint main(void)\n{\n    setlocale(LC_CTYPE, "");\n\n    // Print some debugging information regarding selected locale\n    printf("Current locale for LC_TYPE category: %s\\n", setlocale(LC_CTYPE, NULL));\n    printf("Maximum number of bytes in a multibyte character: %zu\\n", MB_CUR_MAX);\n    printf("Does current encoding support shift states? : %s\\n\\n", mblen(NULL, 0) ? "Yes" : "No");\n\n    int goals_home_teams[] = { 4, 0 };\n    int goals_away_teams[] = { 3, 0 };\n    const char *home_team_names[] = { "Atl\xc3\xa9tico Mineiro", "West Ham United FC" };\n    const char *away_team_names[] = { "Gr\xc3\xa9mio", "Everton FC" };\n\n    for (int i = 0; i < 2; i++)\n    {\n        printf("=> %-*s (%d) vs (%d) \\t%-*s\\n",\n            25 + (int) compensation(home_team_names[i]),\n            home_team_names[i], goals_home_teams[i], goals_away_teams[i],\n            25 + (int) compensation(away_team_names[i]),\n            away_team_names[i]);\n    }\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n
Current locale for LC_TYPE category: en_US.UTF-8\nMaximum number of bytes in a multibyte character: 6\nDoes current encoding support shift states? : No\n\n=> Atl\xc3\xa9tico Mineiro          (4) vs (3)     Gr\xc3\xa9mio                   \n=> West Ham United FC        (0) vs (0)     Everton FC  \n
Run Code Online (Sandbox Code Playgroud)\n

  • 是的,我已经考虑过这一点,但不想用一件大事来做这件事,所以只是想弄清楚是否有办法避免这种情况! (2认同)