2011-01-05 97 views
9

我必須通過一些文本並根據字符模式編寫UTF8輸出。如果我可以使用代碼點並將其轉換爲UTF8,我認爲這很容易。我一直在閱讀unicode和UTF8,但找不到一個好的解決方案。任何幫助將不勝感激。C庫將unicode代碼點轉換爲UTF8?

回答

33

轉換Unicode代碼點爲UTF-8是如此的微不足道的是,製造調用庫可能需要的不僅僅是自己做更多的代碼:

if (c<0x80) *b++=c; 
else if (c<0x800) *b++=192+c/64, *b++=128+c%64; 
else if (c-0xd800u<0x800) goto error; 
else if (c<0x10000) *b++=224+c/4096, *b++=128+c/64%64, *b++=128+c%64; 
else if (c<0x110000) *b++=240+c/262144, *b++=128+c/4096%64, *b++=128+c/64%64, *b++=128+c%64; 
else goto error; 

而且,做你自己意味着你可以調整的API來w的類型你需要的ork(角色在一次?或長字符串?)如果您知道輸入是有效的Unicode標量值,則可以刪除錯誤情況。

另一個方向很難得到正確的。我推薦一種有限自動機方法,而不是典型的位算術循環,有時將無效序列解碼爲真實字符的別名(這非常危險並且可能導致安全問題)。我認爲你應該先嚐試自己編寫它,或者至少在進一步學習之前認真研究UTF-8規範。很多糟糕的設計可能來自將UTF-8當作黑匣子來處理,當整個觀點認爲它不是黑匣子,而是被創建爲具有非常強大的屬性時,許多新的UTF-8編程人員直到看不到他們自己也一直在努力。

+6

@Philipp:是否編寫了更多的代碼來封裝一個庫,以滿足您的界面需求並更好地解決其錯誤?如果你關心瀏覽解碼UTF-8的現有庫代碼,你會發現絕大多數在錯誤的方面是錯誤的,至少30%有嚴重的安全關鍵錯誤。 (這些估計值來自我之前做過的Google代碼搜索。)另外,'iconv'的GNU實現對於字符一次轉換來說速度太慢了,儘管它可以正常工作(儘管有意不符合)進行批量轉換。 – 2011-01-06 16:08:28

+0

我在更高級的版本中拍攝:http://mercurial.intuxication.org/hg/cstuff/raw-file/tip/utf8_encode.c – Christoph 2011-01-06 20:47:51

+2

拒絕非字符可能對您的應用程序有用,但它不是UTF-8規範和一般不正確。 UTF是代碼單元序列(字節或更大的單詞)與「Unicode標量值」之間的一對一映射。 Unicode標量值正好是整數0-0xD7FF和0xE000-0x10FFFF。這一切都是在Unicode標準中定義的,你應該在嘗試實現自己的東西之前閱讀它。 – 2011-01-06 21:37:40

1

哪個平臺?在Windows上,您可以使用WideCharToMultiByte(CP_UTF8,...)

可以說,源代碼點必須用UTF-16編碼,這意味着您必須能夠執行此類編碼。在某些情況下(代理對),這不是微不足道的。

我的理解是,您在給定的代碼頁中有一些文本,並且您想將其轉換爲Unicode(UTF-16)。對?一個MultiByteToWideChar(codePage,sourceText,...)/ WideCharToMultiByte(CP_UTF8,utf16Text,...)往返就可以實現。

+0

我正在使用linux。 – chanux 2011-01-06 03:04:23

+0

@chanux:然後您可以使用'iconv',如其他答案中所述。 – Philipp 2011-01-06 10:53:25

5

iconv可以用我圖。

#include <iconv.h> 

iconv_t cd; 
char out[7]; 
wchar_t in = CODE_POINT_VALUE; 
size_t inlen = sizeof(in), outlen = sizeof(out); 

cd = iconv_open("utf-8", "wchar_t"); 
iconv(cd, (char **)&in, &inl, &out, &outlen); 
iconv_close(cd); 

但我擔心的wchar_t可能不代表Unicode代碼點,但任意值..編輯:我想你可以通過簡單地用一個Unicode源做到這一點:

uint16_t in = UNICODE_POINT_VALUE; 
cd = iconv_open("utf-8", "ucs-2"); 
+2

如果代碼點不在BMP中,該怎麼辦? ucs-2無法表示它。根據平臺,一個wchar_t可能不夠。這就是爲什麼我認爲OP關於瞭解代碼點的假設是錯誤的。因爲這樣,就會詢問用於表示它的編碼問題(UTF-32?UTF-16?顯然不是UTF-8) – 2011-01-05 18:15:56

+1

如果定義了__STDC_ISO_10646__,則wchar_t是Unicode碼值。請注意,如果'wchar_t'是16位,這意味着只支持BMP; UTF-16不是一種可能性。 – 2011-01-05 22:56:42

+1

16位'wchar_t'可以明確用於UTF-16編碼的字符串。所有這一切都意味着,BMP以外的任何代碼點值將使用2個'wchar_t'替代字符並排編碼的字符串進行編碼,就這些了。 Windows API正好運行在這種類型的數據上,並且它工作得很好。 – 2011-01-09 09:31:19