在.NET中,爲什麼是不是真的:爲什麼不是`Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(X))== x`
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(x))
返回原始字節數組對於任意字節數組x
?
它是在回答另一個問題mentioned但響應者並沒有解釋爲什麼。
在.NET中,爲什麼是不是真的:爲什麼不是`Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(X))== x`
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(x))
返回原始字節數組對於任意字節數組x
?
它是在回答另一個問題mentioned但響應者並沒有解釋爲什麼。
字符編碼(UTF8,specificly)可以具有對於相同的代碼點不同的形式。
因此,當您轉換爲字符串並返回時,實際字節可能代表不同(規範)形式。
參見String.Normalize(NormalizationForm.System.Text.NormalizationForm.FormD)
參見:
某些Unicode序列是缺點因爲它們代表相同的字符,所以被認爲是相同的例如,以下被認爲是等效的,因爲任何這些可被用於表示「A」:
"\u1EAF" "\u0103\u0301" "\u0061\u0306\u0301"
然而,序,即,二進制比較考慮這些序列不同,因爲它們包含不同的Unicode代碼值。在執行序號比較之前,應用程序必須規範化這些字符串以將它們分解爲其基本組件。
該頁面有一個很好的樣品,顯示你有什麼編碼總是歸
這是因爲==不會陣列中的每個元素進行比較。它與Encoding.UTF8沒有任何關係。 檢查:
var a = new byte[] { 1 };
var b = new byte[] { 1 };
bool res = a == b;
首先,watbywbarif提到的,你不應該使用==
比較序列,這是行不通的。
但是,即使你(只是看着他們,例如通過使用SequenceEquals()
或)比較正確的陣列,它們並不總是相同的。其中這可能發生的一種情況是,如果x
是無效的UTF-8編碼的字符串。
例如,0xFF
1字節序列是無效的UTF-8。那麼Encoding.UTF8.GetString(new byte[] { 0xFF })
會返回什麼?它是 ,U + FFFD,替換字符。當然,如果你調用該Encoding.UTF8.GetBytes()
,它不給你回0xFF
。
從我+1,很好的例子 – sehe 2012-03-16 16:18:52
我不知道'SequenceEqual'擴展方法,非常有用。 – PyreneesJim 2012-03-16 16:50:46
換個角度,從來到這個就是Encoding
類是設計爲往返數據,但它們被設計用來往返的數據是char
數據編碼爲byte
,而不是周圍的其他方法。這意味着,在所討論的Encoding
的能力範圍內,每個值在byte
值(1或更多)中都具有相應的編碼,這些值將回到完全相同的值char
值。 (值得注意的是,並非所有的Encoding
S能爲所有可能char
值做到這一點 - 例如,只能支持char
值的範圍在[0, 128)
)
所以,如果你開始與性格數據,並且您需要一種方法將其存儲或發送到與字節一起工作的介質(如磁盤上的文件或網絡流),Encoding
是將char
數據轉換爲byte
數據然後再轉回另一端。 (如果你想支持所有可能字符串,則需要使用基於Unicode的Encoding
S的一個,如Encoding.Unicode
或Encoding.UTF8
。)
那麼,這是什麼意思,如果你開始一堆byte
s?那麼,根據所討論的編碼,您正在使用的byte
可能實際上並不是Encoding
將輸出的序列。你需要在Encoding.GetBytes
看作是一種編碼操作和Encoding.GetChars
/Encoding.GetString
爲解碼操作,所以你開始用的字節數組任意並試圖解碼他們。
作爲比喻,請考慮圖像的JPEG文件格式。這具有相似類型的編碼和解碼,其中在這種情況下解碼的數據不是string
而是圖像。所以,如果你使用任意字節串,它有可能被解碼爲JPEG圖像的機會是多少?顯然,答案非常渺茫。更有可能的是,你的字節最終會沿着解碼器的一條路走下去,說道:「哇,我不希望那個字節在另一個之後」,並且它將盡最大努力在假設下處理數據它是一個有效的JPEG文件,以某種方式受到損壞。
當您將任意字節數組轉換爲字符串時,會發生完全相同的情況。 UTF-8編碼具有關於如何對值128和以上進行編碼的具體規則,並且其中的一條規則說,在匹配諸如110xxxxx
,1110xxxx
或11110xxx
之類的模式之後,只會看到匹配位模式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.ToBase64String
和Convert.FromBase64String
公開。
您將鏈接到關於ASCII的討論的答案,而不是UTF-8。 – svick 2012-03-16 16:01:33
你甚至可以用'=='來比較字節數組嗎?這可能只是比較它們的引用,你可能必須做一個循環來比較數組中的每個元素是否相等。 – Matthew 2012-03-16 16:06:19
@Matthew [該答案](http://stackoverflow.com/a/3946274/85371)的要點似乎是編碼可能會有所不同。是的,示例代碼有缺陷/倒退。 – sehe 2012-03-16 16:14:04