簡體   English   中英

如何用'%s'說明符打印一個unicode字符串?

[英]How to printf a unicode string with '%s' specifier?

我試圖調用printf()來輸出使用%s的Unicode字符/字符串,但它不會打印任何內容。

如果我像這樣調用printf()

 printf("\xE2\x98\xA0")

我得到了一個

但是,如果我像這樣使用%ls

printf("%ls", "☠")  /* or */
printf("%ls", L"☠") /* or */
printf("%ls", L"\xE2\x98\xA0")

我沒有打印出來;

另外,如何在其中聲明帶有Unicode字符的wchar_t字符串? wchar_t wstro[50] = L"☠"不起作用。

我需要malloc()一個wchar_t然后將Unicode數據放入其中嗎?

您將Unicode與UTF-8混淆,並且兩者都與wchar_t混淆。

Unicode是抽象的東西,帶有代碼點,結合了字符和其他屬性。

UTF-8是編碼Unicode的常用方法,它與ASCII兼容(僅限ASCII字符串),並且與C字符串兼容(因此零終止(字符串中沒有其他0字節)。 \\xE2\\x98\\xA0是UTF-8表示。

字符可能也以UTF-8編碼。 這取決於您的編輯器,但編輯通常不使用wchar_t。

所以:使用UTF-8你應該只使用%s而不是%ls 所以你的3次嘗試都是錯誤的。

我一般,使用UTF-8等char*和普通的字符串函數(只是在隨機字節上不斷字符串,但這意味着在隨機UTF-8代碼點之后如果后面跟着一些組合代碼點也不會破壞字符串。

您可以使用wchar_t,但通常使用使用wchar_t的協議,但特別是在這種情況下,您應該格外小心,因為wchar_t的大小無法與所需的字符大小(預期編碼)兼容[例如您的系統等等] wchar_t可能只有2個字節,但是你可以使用UCS2,但不能使用UTF-32,或者相反,如果系統將wchar_t定義為4個字節)。

所以保持簡單並嘗試僅使用UTF-8,並將其用作普通的C字符串。

這個答案假設您在MS Windows中工作


很遺憾我們在2018年,這些東西仍然無法正常工作。 但這是事物的狀態:

printf("\\xE2\\x98\\xA0"); (與printf("%s", "\\xE2\\x98\\xA0"); )相同printf("%s", "\\xE2\\x98\\xA0"); )有效,因為您只輸出3個字符到輸出流。 C語言中沒有出現Unicode或特殊字符處理。 您的終端環境在輸出中查找UTF-8字符串並相應地選擇顯示字形。

類似地,如果您將輸出寫入文件(使用fprintf或流重定向),您會看到該文件包含0xE2, 0x98, 0xA0然后您可以選擇使用將UTF-8轉換為顯示字形的文本文件查看器。

這部分都很好,您可以(也可能應該)編寫程序,只將UTF-8編碼的字符寫入FILE流。


當我們想要輸出wchar_t字符時,問題就開始了。 理論上這應該工作:

printf("%ls", L"\u2620");   

應該發生的是調用wcstombs將unicode代碼點序列轉換為多字節序列。 但是使用哪種多字節格式? UTF-8現在已經無處不在,但在過去還有其他格式,如ShiftJIS,Big-5等。

您必須使用setlocale指定多字節格式。 locales的細節是實現定義的。

這是踢球者。 對於一般的UTF-8輸出,Windows不支持C語言環境 如果您嘗試setlocale(LC_CTYPE, ".65001"); 它只是不起作用。

您可以使用受支持的語言環境輸出Unicode的某些子集。 例如使用Japanese_Japan.932 的MSDN示例有效,將Unicode輸入輸出為Shift-JIS。 (不是UTF-8)。

更糟糕的是,如果您使用Windows API函數WideStringToMultiByte ,它確實接受CP_UTF8的“區域設置”。 您可以使用此功能轉換L"\☠"; char緩沖區和printf ,生成UTF-8輸出。

但是當然你不能“插入”到FILE流處理,它只調用wcstombs而不是WideStringToMultiByte

他們為什么不允許".UTF-8"作為wcstombs的語言環境? 惡意行為? 誰知道。


理論上應該起作用的下一件事是:

FILE *fp = fopen("a.txt", "w");
fwide(fp, 1);
fwprintf(fp, L"\u2620");

但實際上,MS運行時實際上並沒有對fwide做任何事情; 它不支持面向廣播的流。 wprintf系列的Microsoft實現實際上只輸出窄字符,而不是寬字符,並且它們使用與窄printf系列相同的wcstombs方法。

所以,那個代碼不起作用,而日本wcstombs例子中的代碼, fwprintf(fp, L"\㘃"); (使用.932 CP設置)輸出多字節序列而不是原始寬字符。

要通過stdio.h API編寫UTF-16文件,您實際上別無選擇,只能使用窄字符並將其視為二進制文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM