[英]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.