2013-03-16 33 views
1

UTF-16字符串所以我有標準的C字符串:從創建的char *

char* name = "Jakub"; 

我想將它轉換爲UTF-16。我想通了,那UTF-16會是的兩倍長 - 一個字符需要兩個字符。
所以我創建另一個字符串:

char name_utf_16[10]; //"Jakub" is 5 characters 

現在,我相信與ASCII字符我只會用低字節,所以對於所有的人就會像74 00J等。抱着這個信念,我可以讓這樣的代碼:

void charToUtf16(char* input, char* output, int length) { 
    /*Todo: how to check if output is long enough?*/ 
    for(int i=0; i<length; i+=2) //Step over 2 bytes 
    { 
     //Lets use little-endian - smallest bytes first 
     output[i] = input[i]; 
     output[i+1] = 0; //We will never have any data for this field 
    } 
} 

但是,在這個過程中,我與"Jkb"結束。我知道沒有辦法正確測試 - 我剛剛發送了字符串到Minecraft Bukkit Server。而這也正是它在斷開說:

13時34分19秒] [INFO斷開JKB? [/127.0.0.1:53215]:過時的服務器!

注意:我知道Minecraft使用big-endian。上面的代碼僅僅是一個例子,實際上,我在課堂上實現了我的轉換。

+5

您應該使用現有的UTF-16編碼器,創建一個強大的編碼器並非易事。 – Esailija 2013-03-16 12:57:17

+0

如果我希望能夠使用整個字符表,那不是真的。但我只想在256個ASCII字符中!這個任務也很複雜嗎? – 2013-03-16 13:00:52

+1

顯然是的:P – Esailija 2013-03-16 13:04:33

回答

-2
output[i] = input[i]; 

這將輸入的每一個字節的其他分配,因爲你增加i由2所以難怪你獲得"Jkb"。 你可能想寫:

output[i] = input[i/2]; 
+0

哦,不,我怎麼會這麼跛腳。謝謝:) – 2013-03-16 13:28:24

+0

這並不容易......轉換依賴於輸入編碼,只有在原始編碼基於ASCII編碼的情況下,填充0才能用於範圍0-127內的字符。此外,標準庫已經提供了'mbstowcs',所以實現像這樣的自定義(破解)解決方案是沒有用的。 – 2013-03-16 13:49:53

+0

其中OP已經提到過。解決方案只需要適合OP的情況,它不一定適用於所有可能的情況。 – Dialecticus 2013-03-16 13:54:09

4

爲什麼你想使自己的Unicode轉換功能時,這個孤單現有的C/C++的功能,如mbstowcs()包含在<cstdlib>

如果你仍然想使你自己的東西,然後看看Unicode協會的開源代碼,可以在這裏找到:

Convert UTF-16 to UTF-8 under Windows and Linux, in C

+0

'mbstowcs'不一定是utf-16,因爲它是語言環境特定的。 C++ 11有'codecvt',這可能是一個更好的例子。 – prideout 2013-07-06 16:53:56

+0

@prideout所以,在韓國,中國和日本,它可能是UTF-32? – 2013-07-06 18:29:42

+0

'mbstowcs'中的寬字符可能是4個字節。例如,「zh_CN.UTF-8」和「zh_CN.GB2312」對於中國來說都是有效的語言環境,但它們使用不同的字符編碼。 – prideout 2013-07-07 00:27:57

3

在我回答你的問題,可以這樣考慮:

這方面的編程充滿了人工陷阱。理解ASCII,UTF7/8和ANSI /'MultiByte字符串(MBCS)'之間的區別是很有意義的,所有這些對講英語的程序員來說都會看起來和感覺完全相同,但如果它們是介紹給歐洲或亞洲用戶。

ASCII:字符在32-127範圍內。只有一個字節。線索的名字是,它們對美國人來說很好,但不適合在世界其他地方使用。

ANSI/MBCS:這就是'代碼頁'的原因。字符32-127與ASCII相同,但是可以在128-255範圍內具有字符以及用於附加字符,並且128-255範圍中的一些可以用作標記字符繼續的標誌成第二,第三甚至第四字節。要正確處理字符串,您需要字符串字節和正確的代碼頁。如果嘗試使用錯誤的代碼頁處理字符串,則不會有正確的字符,並且會誤解字符是一個,兩個甚至四個字節字符。

UTF7/8:這些是21比特的Unicode字符點8位寬的格式。在UTF-7和UTF-8 unicode字符中,長度可以介於1到4個字節之間。 UTF編碼優於ANSI/MBCS的優點是不存在由代碼頁造成的歧義。每個腳本中的每個字形都有一個唯一的unicode代碼點,這意味着不可能通過解釋具有不同區域設置的不同計算機上的數據來破壞字符集。

所以要開始回答你的問題:

  1. 而你正在做的假設,你的char *只會點爲ASCII字符串,這是一個非常危險的抉擇,用戶控制輸入​​的數據,而不是程序員。 Windows程序將默認將其存儲爲MBCS。

  2. 正在製作的第二個假設是一個UTF-16編碼將是一個8位編碼的大小的兩倍。這通常不是一個安全的假設。取決於源編碼,UTF-16編碼可能是兩倍的大小,可能小於兩倍的大小,並且在一個極端的例子中可能實際上更短。

那麼,什麼是安全解決方案?

安全的選擇是在內部實現應用程序爲Unicode。在Windows上,這是一個編譯器選項,然後意味着您的Windows控件都使用wchar_t *字符串作爲其數據類型。在Linux上,我不確定你總是可以使用殺人圖形和操作系統庫。您還必須使用wcslen()函數來獲取字符串的長度等。當您與外部世界進行交互時,請確保使用的字符編碼精確。

要回答你的問題就成爲改變到,我該怎麼辦的問題,當我接收非UTF-16數據?

首先,是關於你在做它的格式是什麼的假設很清楚了嗎?其次,接受有時轉換爲UTF-16可能會失敗的事實。

如果您對源格式有所瞭解,則可以選擇相應的win32或stl轉換器來轉換格式,然後在使用結果之前查找轉換失敗的證據。例如mbstowcs in或MultiByteToWideChar()在窗口上。然而,安全地使用這兩種方法意味着你需要了解所有上述答案。

所有其他選項引入風險。使用mbcs字符串,您將使用一個代碼頁輸入數據字符串,並使用不同的代碼頁進行處理。假設有ASCII數據,並且當你遇到一個非ASCII字符時,你的代碼將會中斷,並且你將會爲用戶的短命「責備」用戶。

相關問題