一個文字轉十六進位範例會將字串中的每個字元重新表示為其 UTF-8 位元組的兩位十六進位表示,因此 ASCII 字母 "H" 會變成位元組 48,而 "i" 會變成 69,對於輸入 "Hi" 產生連續的輸出 4869。這個對應關係來自 WHATWG 編碼標準,該標準將 UTF-8 定義為一種可變寬度編碼,其中一個位元組承載 ASCII,兩個位元組承載大部分帶有變音符號的拉丁字母,三個位元組承載基本多文種平面的絕大部分字符,而四個位元組則承載補充字符,例如表情符號。因此,文字轉十六進位範例不僅需要顯示輸入的字母,還需要顯示產生的位元組數量,因為一個四位元組的表情符號字串所佔用的十六進位位數遠多於四個 ASCII 字母。Text To HEX 工具使用標準化的 TextEncoder API 在瀏覽器中套用這個精確的 UTF-8 位元組對應,因此任何文字轉十六進位範例中顯示的數字都反映了嚴格解碼器會讀取的位元組。

text to hex example
文字轉十六進位範例:UTF-8 位元組在實際應用中的樣貌

解讀輸出:位元組數量、取代數量與輸出長度

典型的文字轉十六進位範例會在數字旁附上三項支援資料:UTF-8 位元組數量、被取代為 U+FFFD 的孤立代理碼元數量,以及格式化後的輸出長度。位元組數量說明在純文字格式下,結果包含多少個兩位數的十六進位配對。取代數量只有在輸入包含未配對的 UTF-16 代理碼元時才不為零,這在輸入文字中很罕見,但可能出現在格式錯誤或以程式產生的字串中。格式化後的輸出長度取決於所選擇的格式,並在建構輸出字串之前計算。純文字格式寫入 2n 個位數,其中 n 是位元組數。空白分隔格式寫入 3n−1 個字元,因為每對之間以一個 ASCII 空白分隔。0x 前綴格式寫入 5n−1 個字元,因為每個標記為 "0xNN" 後接一個空白,但最後一個標記之後除外。

逐步演練:逐步編碼一個簡短字串

以輸入 "Hi" 為例。瀏覽器接收兩個 UTF-16 碼元,每個字元一個。TextEncoder 將其轉換為兩個 UTF-8 位元組,因為這兩個字元都落在 ASCII 範圍內,所以每個字元佔用一個位元組。"H" 的位元組在十六進位中為 48,而 "i" 的位元組為 69。在純文字格式中,結果是連續的字串 4869。在空白分隔格式中,結果是 "48 69",兩對之間有一個 ASCII 空白。在 0x 前綴格式中,結果是 "0x48 0x69",最後一個標記之後沒有分隔符。使用格式長度公式,當 n 等於 2 時,純文字格式給出 2×2 = 4 個字元,空白分隔格式給出 3×2−1 = 5 個字元,0x 前綴格式給出 5×2−1 = 9 個字元。顯示的位元組數量為 2,格式化後的輸出長度與所選的格式相符。這三種格式都不會改變位元組本身;只有標點和空白會改變。

如何透過三個步驟將文字轉換為十六進位

  1. 在輸入欄位中輸入來源文字,包括該欄位所接受的所有 Unicode 字元、空白字元、NUL 位元組或標點符號。
  2. 選擇輸出格式(連續、空白分隔或 0x 前綴),並選取十六進位數字為小寫或大寫。
  3. 編碼文字,檢視位元組數量及任何孤立代理的取代警告,然後複製完整的十六進位輸出。

格式與字母大小寫一覽

變更格式或字母大小寫絕不會改變編碼後的 UTF-8 位元組;它只會改變格式化後的輸出長度以及數字的外觀。下表使用相同的輸入位元組摘要這三種格式:

格式標記形式長度公式"Hi" 的範例
連續每個位元組兩位數2n4869
空白分隔每個位元組兩位數,以 ASCII 空白分隔3n−148 69
0x 前綴每個位元組一個 "0xNN",以 ASCII 空白分隔5n−10x48 0x69

對於一個較大的演算案例,格式長度公式可以直接套用於多位元組輸入。以一個單位元組的 ASCII 字元為例,例如 "A"(位元組 41)。純文字格式產生 2×1 = 2 個字元,空白分隔格式產生 3×1−1 = 2 個字元,0x 前綴格式產生 5×1−1 = 4 個字元。純文字與空白分隔格式在單一位元組的情況下長度相同,因為沒有內部分隔符需要加入。對於一個四位元組的表情符號,例如 U+1F600,純文字格式產生 2×4 = 8 個字元,空白分隔格式產生 3×4−1 = 11 個字元,0x 前綴格式產生 5×4−1 = 19 個字元。純文字與空白分隔兩欄恰好相差 n−1 個 ASCII 空白,而 0x 前綴欄則比空白分隔形式多出 2n 個字元。需要查閱許多不同輸入的實際位元組值的讀者,可以參考 Text to Hex Cheat Sheet: UTF-8 Values and Format Reference 以取得更廣泛的參考資料。

依字元類型分類的範例

不同的字元類別在任何文字轉十六進位範例中會產生不同的長度。這個對應關係是由 UTF-8 規格定義,而非由工具定義,因此相同的輸入總是會產生相同的位元組:

  • ASCII,例如 U+0041 "A",編碼為一個位元組 41。
  • 帶有變音符號的拉丁字母,例如 U+00E9 "é",編碼為兩個位元組 c3 a9,因為 0xE9 落在 ASCII 範圍之外,但位於兩位元組的窗口內。
  • 位於基本多文種平面內的 CJK,例如 U+4F60 "你",編碼為三個位元組 e4 bd a0,因為該碼位高於兩位元組的範圍。
  • 補充字符,例如 U+1F600 "😀",編碼為四個位元組 f0 9f 98 80,因為該碼位超過 U+FFFF。

大寫模式只會將字母 a 到 f 變更為 A 到 F;無論大小寫設定為何,位元組值本身以及小寫的 0x 標記都保持不變。因此,以大寫寫成的 0x1f600 是 0x1F600,而位元組 0xc3 在大寫模式下為 C3。

為什麼某些位元組在文字轉十六進位範例中看起來出乎意料

有幾種輸入會產生令讀者驚訝的十六進位,這些讀者預期的是簡單的每字元一個位元組的行為。NUL 字元 U+0000 編碼為單一位元組 00,而不是空字串。CR、LF、Tab 和空白會按照它們在輸入中出現的順序編碼,不會被正規化;CR LF 保持為 0d 0a,而不是合併為 0a。組合附加符號不會被折疊為其組合形式,因此 "e" 後接 U+0301(組合銳音符號)的序列會編碼為 65 cc 81,而不是被變更為預先組合的 "é" U+00E9。孤立的 UTF-16 代理不是有效的 Unicode 純量值,標準化的編碼器會將每次出現取代為 U+FFFD,其 UTF-8 位元組為 ef bf bd,而該工具會顯示一個可見的取代數量,因為這些位元組無法解碼回原始的孤立碼元。最後,編碼器不會在前面加上 BOM;如果您的輸入本身以 U+FEFF 開頭,那三個位元組 ef bb bf 會以一般資料的形式出現,因為該字元是輸入字串的一部分。用於此轉換的瀏覽器 API 在 MDN TextEncoder.encode 參考資料 中有說明。

透過配套解碼器對文字轉十六進位範例進行往返轉換

乾淨的往返轉換要求位元組能夠解碼回原始字串。配套的 Hex to Text 工具使用明確的分隔符與 0x 前綴規則讀取這些位元組,並且僅解碼格式正確的 UTF-8。由於 TextEncoder 不會新增 BOM,因此以 U+FEFF 開頭的輸入會產生前導位元組 ef bb bf,配套解碼器會根據其文件中記錄的 BOM 行為來消耗這些位元組,而不是將其視為一般資料。對於精確的往返轉換,原始文字不應以 U+FEFF 開頭,且應僅包含格式正確的 Unicode,不含孤立代理。其他資料會原封不動地通過:此工具不會套用正規化、新行轉換、修剪、大寫/小寫折疊、逸出解析或區域設定感知的重寫,因此文字轉十六進位範例所產生的位元組序列,與嚴格的 UTF-8 解碼器將讀取的序列相同。

如需更深入的探討,請參閱 Decode UTF-8 Bytes Without Silent Replacement Characters。