繁体   English   中英

寻找支持UTF8的格式化函数,如printf()等

[英]Looking for UTF8-aware formatting functions like printf(), etc

我在使用C标准库格式化函数(如sprintf())处理包含非ASCII字符的UTF-8字符串时发现了一个有趣的问题:

printf()系列的功能不知道utf-8并根据字节数而不是字符处理所有内容。 因此格式不正确。

简单的例子:

#include <stdio.h>

int main(int argc, char *argv[])
{
    const char* testMsg = "Tääääßt";
    char buf[1024];
    int len;

    sprintf(buf, "|%7.7s|", testMsg);
    len = strlen(buf);
    printf("Result=\"%s\", len=%d", buf, len);

    return 0;
}

结果是:

 Result="|Täää|", len=7

很可能你们中的一些人会建议将应用程序从char转换为wchar_t并使用fwprintf()等,但由于现有的巨大应用程序,这绝对是不可能的。 我可以想象编写一个在内部使用这些函数的包装器,但这会非常棘手并且非常低效。

因此,最好的解决方案是替换标准C库的格式化功能的UTF-8。

目前我正在研究QNX 6.4,但回复了其他操作系统。 例如Linux,也非常受欢迎。

好吧,一旦你要求printf对Unicode字符进行智能填充,就会遇到重大问题。 像他们说的那样,

w͢͢͝h͡o͢͢͡͡k̵͟n̴͘ǫw̸̛s͘w̧̕a҉̡͢ţ̕ho̵r͏̵rors̡̡lį̶e͟͟͟͟in͢͢t̕h̷̡͟e͟͟d̛a͜r̕͡k̢̨̢̨h̴e͏a̷̢̡rt͏͏̴̷̵̶̸̸̷̧̧̧̛̛̛͘͘͘͜͜͜͠͏̷͏̡̡̡͝͝͝͞͞͞͞

  • Tääääßt有多少个Unicode字符? 好吧,它可以是7到11之间的任何地方,具体取决于它的编码方式。 每个ä可以写成U + 00E4,这是一个字符,或者它可以写成U + 0061 U + 0308,这是两个字符。 所以你的下一个希望是计算字形集群。 (不,标准化不会使问题消失。)

  • 但是,字形簇有多宽? 显然, a是一列宽。 U + 200B应为零列宽,这是一个“零宽度”空间。 每个ひらがな应该是两列宽吗? 它们通常位于终端仿真器中。 将ひらがな格式化为7列时会发生什么,你会得到"ひらが " ,这会增加一个空格,还是得到"ひらが" ,这只是6列?

  • 如果您剪切混合了RTL和LTR文本的内容,您是否应该重新设置文本方向? 你会怎样做? (某些终端模拟器,例如Apple的,支持从左到右和从右到左文本的混合。)

  • 截断文字的目的是什么? 您是在尝试向用户显示有限空间中的字符串,还是在尝试编写使用固定宽度字段的格式?

基本上,如果你想将Unicode文本剪切成块,你不应该使用像printf (或wprintf ,这可能更糟)这样简单的东西。 使用LibICU( 网站 )迭代您想要的休息时间。 编写UTF-8识别版本的printf会要求您提供各种不需要的麻烦。

以下C99代码片段定义了函数u8printf,其中格式说明符(如%10s)产生10个utf-8代码点,即字符而不是字节。 在调用此例程之前,不要忘记在某处设置setlocale(LC_ALL,“”)的语言环境。 这是有效的,因为wprintf在内部使用wchar_t。 您可以用类似的方式定义u8fprintf和u8sprintf。 如果你想在没有C99可变长度数组的情况下编写这个,那么也可以使用malloc / free的合适组合。

int u8printf(char *fmt,...){
    va_list ap;
    va_start(ap,fmt);
        int n=mbstowcs(0,fmt,0);
        if(n==-1) return -1;
        wchar_t wfmt[n+1];
        mbstowcs(wfmt,fmt,n+1);
        for(int m=128;m<=32768;m*=2){
            wchar_t wbuf[m];
            int r=vswprintf(wbuf,m,wfmt,ap);
            if(r!=-1) {
                char buf[m*4];
                wcstombs(buf,wbuf,m*4);
                fputs(buf,stdout);
                return r;
            }
        }
        return -1;
    va_end(ap);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM