2012-03-16 70 views
5

在.NET中,爲什麼是不是真的:爲什麼不是`Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(X))== x`

Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(x)) 

返回原始字節數組對於任意字節數組x

它是在回答另一個問題mentioned但響應者並沒有解釋爲什麼。

+0

您將鏈接到關於ASCII的討論的答案,而不是UTF-8。 – svick 2012-03-16 16:01:33

+1

你甚至可以用'=='來比較字節數組嗎?這可能只是比較它們的引用,你可能必須做一個循環來比較數組中的每個元素是否相等。 – Matthew 2012-03-16 16:06:19

+0

@Matthew [該答案](http://stackoverflow.com/a/3946274/85371)的要點似乎是編碼可能會有所不同。是的,示例代碼有缺陷/倒退。 – sehe 2012-03-16 16:14:04

回答

1

字符編碼(UTF8,specificly)可以具有對於相同的代碼點不同的形式。

因此,當您轉換爲字符串並返回時,實際字節可能代表不同(規範)形式

參見String.Normalize(NormalizationForm.System.Text.NormalizationForm.FormD)

參見:

某些Unicode序列是缺點因爲它們代表相同的字符,所以被認爲是相同的例如,以下被認爲是等效的,因爲任何這些可被用於表示「A」:

"\u1EAF" 
"\u0103\u0301" 
"\u0061\u0306\u0301" 

然而,序,即,二進制比較考慮這些序列不同,因爲它們包含不同的Unicode代碼值。在執行序號比較之前,應用程序必須規範化這些字符串以將它們分解爲其基本組件。

該頁面有一個很好的樣品,顯示你有什麼編碼總是歸

+0

爲什麼兩種方法中的任何一種會改變字符串的形式? – svick 2012-03-16 16:08:25

+0

@svick不要問我。我沒有檢查文件,以確保它不會,雖然 – sehe 2012-03-16 16:15:00

+0

我認爲這不會發生。這是因爲這些不同的形式不是各種編碼的屬性,而是Unicode本身。所以,一個字符可以表示爲不同的碼點序列。但是,當使用特定的編碼時,單個代碼點序列只能以一種方式表示爲字節序列。 – svick 2012-03-16 16:20:39

1

這是因爲==不會陣列中的每個元素進行比較。它與Encoding.UTF8沒有任何關係。 檢查:

var a = new byte[] { 1 }; 
var b = new byte[] { 1 }; 
bool res = a == b; 
3

首先,watbywbarif提到的,你不應該使用==比較序列,這是行不通的。

但是,即使你(只是看着他們,例如通過使用SequenceEquals()或)比較正確的陣列,它們並不總是相同的。其中這可能發生的一種情況是,如果x是無效的UTF-8編碼的字符串。

例如,0xFF 1字節序列是無效的UTF-8。那麼Encoding.UTF8.GetString(new byte[] { 0xFF })會返回什麼?它是 ,U + FFFD,替換字符。當然,如果你調用該Encoding.UTF8.GetBytes(),它不給你回0xFF

+0

從我+1,很好的例子 – sehe 2012-03-16 16:18:52

+1

我不知道'SequenceEqual'擴展方法,非常有用。 – PyreneesJim 2012-03-16 16:50:46

1

換個角度,從來到這個就是Encoding設計爲往返數據,但它們被設計用來往返的數據是char數據編碼爲byte,而不是周圍的其他方法。這意味着,在所討論的Encoding的能力範圍內,每個值在byte值(1或更多)中都具有相應的編碼,這些值將回到完全相同的值char值。 (值得注意的是,並非所有的Encoding S能爲所有可能char值做到這一點 - 例如,只能支持char值的範圍在[0, 128)

所以,如果你開始與性格數據,並且您需要一種方法將其存儲或發送到與字節一起工作的介質(如磁盤上的文件或網絡流),Encoding是將char數據轉換爲byte數據然後再轉回另一端。 (如果你想支持所有可能字符串,則需要使用基於Unicode的Encoding S的一個,如Encoding.UnicodeEncoding.UTF8。)

那麼,這是什麼意思,如果你開始一堆byte s?那麼,根據所討論的編碼,您正在使用的byte可能實際上並不是Encoding將輸出的序列。你需要在Encoding.GetBytes看作是一種編碼操作和Encoding.GetChars/Encoding.GetString解碼操作,所以你開始用的字節數組任意並試圖解碼他們。

作爲比喻,請考慮圖像的JPEG文件格式。這具有相似類型的編碼解碼,其中在這種情況下解碼的數據不是string而是圖像。所以,如果你使用任意字節串,它有可能被解碼爲JPEG圖像的機會是多少?顯然,答案非常渺茫。更有可能的是,你的字節最終會沿着解碼器的一條路走下去,說道:「哇,我不希望那個字節在另一個之後」,並且它將盡最大努力在假設下處理數據它是一個有效的JPEG文件,以某種方式受到損壞。

當您將任意字節數組轉換爲字符串時,會發生完全相同的情況。 UTF-8編碼具有關於如何對值128和以上進行編碼的具體規則,並且其中的一條規則說,在匹配諸如110xxxxx,1110xxxx11110xxx之類的模式之後,只會看到匹配位模式10xxxxxx的字節,其「引入」多字節序列(表示單個char的多個byte)。因此,如果您的數據包含一個與10xxxxxx匹配的字節不符合請遵循預期的「引入者」之一,編碼器只能假設數據受到某種損壞。它有什麼作用?它插入一個字符,說:「編碼數據出錯了,我盡力了,這是錯誤的地方。」設計Unicode的人期待這個確切的場景,並創建一個具有這個確切含義的字符:Replacement Character

所以,如果你想在char個字符串往返您byte S和這種情況下遇到,違規byte的實際值丟失,而是一個替換字符插入。當您嘗試將string變回byte陣列時,它將編碼替換字符,而不是原始數據。原始數據丟失。

你在找什麼是編碼&解碼關係,在另一個方向工作。 Encoding用於獲取char數據並找到一種方法將其臨時存儲爲byte數據。如果您想採取byte數據並找到將其臨時存儲爲char數據的方法,則需要爲該特定目的設計的編碼。幸運的是,這些存在。維基百科有一個fairly comprehensive list的選項。 :-)

在.NET Framework中,最簡單和最易於訪問的選項是MIME Base-64編碼,該編碼通過Convert.ToBase64StringConvert.FromBase64String公開。

相關問題