簡體   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