位元組順序記號

本頁使用了標題或全文手工轉換
維基百科,自由的百科全書

位元組順序記號(英語:byte-order markBOM)是位於碼點U+FEFF統一碼字符的名稱。當以UTF-16UTF-32來將UCS/統一碼字符所組成的字串編碼時,這個字符被用來標示其位元組序。它常被用來當做標示文件是以UTF-8UTF-16UTF-32編碼的記號。

位元組順序記號通常有幾種涵義[1]

  1. 在16位元和32位元的情況下,文字流的位元組順序
  2. 表示文字流非常有可能是Unicode編碼。
  3. 使用的是哪一種Unicode字元編碼

位元組順序記號的使用是選擇性的。它的存在會干擾那些不希望檔案開頭出現非ASCII字元、但可以用其他方式處理文字流的軟體對於UTF-8的使用。

Unicode可以以8位元、16位元或32位元整數為單位進行編碼。對於16位元和32位元的表示方法,從任意來源接收文本的電腦需要知道整數是以何種位元組順序編碼的。位元組順序記號的編碼方式與文件檔案的其他部分相同,如果它的位元組被調換,就會變成一個非字元的Unicode碼位。因此,訪問文本的過程中,可以透過檢查這頭幾個位元組來確定位元組順序,而不需要文字流本身以外的一些約定或元資料。一般來說,如果有必要,接收資料的電腦會將位元組換成自己的位元組順序,不再需要位元組順序記號進行處理。

每個Unicode編碼(包括Unicode標準以外的編碼,如UTF-7,見下表)的BOM位元組序列都不一樣,而且這些序列都不可能出現在以其他編碼儲存的文字流的開頭。因此,在文字流的開頭放置一個編碼的BOM,可以表明文本是Unicode,並識別所使用的編碼方案。這種對BOM字元的使用被稱為「Unicode簽名」[2]

使用[編輯]

字符U+FEFF如果出現在字節流的開頭,則用來標識該字節流的字節序,是高位在前還是低位在前。如果它出現在字節流的中間,則表達零寬度非換行空格的意義,用戶看起來就是一個空格。從Unicode3.2開始,U+FEFF只能出現在字節流的開頭,只能用於標識字節序,就如它的名稱——字節順序標記——所表示的一樣;除此以外的用法已被捨棄。取而代之的是,使用U+2060來表達零寬度無斷空白。

UTF-8[編輯]

UTF-8中,雖然在 Unicode 標準上允許位元組順序記號的存在[3],但實際上並不一定需要[4]。UTF-8編碼過的位元組順序記號則被用來標示它是UTF-8的文件。它只用來標示一個UTF-8的檔案,而不用來說明位元組順序[5]。但同時,該標準也不建議在有位元組順序記號的情況下將其刪除,以便在不同的編碼之間轉換時不會丟失資訊,並讓依賴位元組順序記號的程式能順利運作[6][7]。IETF建議,如果一個協議(a)總是使用UTF-8,或者(b)有一些其他方法來表明正在使用的編碼,那麼它「應該禁止使用U+FEFF作為簽名」[8]。 許多視窗程式(包含記事本)會需要添加位元組順序記號到UTF-8檔案,否則將無法正確解析編碼,而出現亂碼。然而,在類Unix系統(大量使用文本文件,用於檔案格式,用於行程間通訊)中,這種做法則不被建議採用。因為它會妨礙到如解譯器腳本開頭的Shebang等的一些重要的碼的正確處理。它亦會影響到無法識別它的程式語言。如gcc會報告源碼檔開頭有無法識別的字符。而在PHP中,如果沒有啟用輸出緩衝(output buffering),它會使得頁面內容開始被送往瀏覽器(即:用戶標頭檔已被送出),這使PHP腳本無法指定用戶標頭檔(HTTP Header)。位元組順序記號在UTF-8中被表示為序列0xEF 0xBB 0xBF,對大部分未準備好處理UTF-8的文本編輯器網頁瀏覽器而言,在ISO-8859-1的環境中則會顯示

Unicode標準允許在UTF-8中使用BOM,但並不要求或推薦使用它。位元組順序在UTF-8中沒有任何意義,所以它在UTF-8中的唯一用途是在開始時發出信號,表明文本流是用UTF-8編碼的,或者表明它是從包含可選BOM的文本流轉換到UTF-8的。該標準也不建議在有BOM的情況下將其刪除,以便在不同的編碼之間往返不會丟失信息,並使依賴BOM的代碼繼續工作。 IETF建議,如果一個協議要麼(a)總是使用UTF-8,要麼(b)有一些其他方法來表明正在使用的編碼,那麼它 "應該禁止使用U+FEFF作為簽名"。

UTF-8是一種稀疏的編碼,意思是很大一部分可能的字元組合不會產生有效的UTF-8文本。任何其他編碼的二進制資料和文本都可能包含UTF-8無效的字元序列,唯一的例外是當文本純粹由ASCII範圍的字元組成的時候。因為所有的現代編碼都使用ASCII範圍的位元組來表示ASCII字元,所以無論發出這些位元組的系統打算使用什麼編碼,純ASCII的文本都可以被安全地解釋為UTF-8。由於這些考慮,使用啟發式的分析方法可以很有把握地檢測出文件是否使用UTF-8,而不需要加入BOM。 另一方面,微軟的編譯器[9]和解釋器,以及許多Microsoft Windows上的軟體,如記事本,都將BOM視為一個必要的神奇數字,而不是使用啟發式分析法。這些工具在將文本保存為UTF-8時添加了BOM,並且只有在BOM存在或是文件只包含ASCII字元時才能解釋UTF-8。Windows PowerShell(截至5.1版本)在保存UTF-8的XML文件檔時,會添加一個BOM。然而,PowerShell Core 6在一些cmdlets上增加了一個-Encoding開關,稱為「utf8NoBOM」,這樣就可以在沒有BOM的情況下保存文件檔。Google文件在將文件檔轉換為純文本文件以供下載時也會添加BOM。

UTF-16[編輯]

UTF-16中,位元組順序記號被放置為檔案或文字串流的第一個字符,以標示在此檔案或文字串流中,以所有十六位元為單位的字碼的端序(位元組順序)。如果試圖用錯誤的位元組順序來讀取這個流,位元組將被調換,從而產生字元U+FFFE,這個字元被Unicode定義為「非字元」,不應該出現在文本中。例如,值為U+FFFE的碼位被保證將不會被指定成一個統一碼字元。這意味著0xFF0xFE將只能被解釋成小端序中的U+FEFF(因為不可能是大端序中的U+FFFE)。

  • 如果十六位元單位被表示成大端序,這位元組順序記號字符在序列中將呈現0xFE,其後跟著0xFF(其中的0x用來標示十六進位)。
  • 如果十六位元單位使用小端序,這個位元組序列為0xFF,其後接著0xFE

這兩個序列都不是有效的UTF-8,所以它們的出現表明該文件不是用UTF-8編碼的。

對於網際網路號碼分配局註冊的字元集UTF-16BE和UTF-16LE,不應該使用位元組順序記號標記,因為這些字元集的名稱已經決定了位元組順序。如果在這樣的文本串流中的任何地方遇到U+FEFF,將被解釋為一個「零寬度無斷點空間」。

如果沒有位元組順序記號,可以透過搜索ASCII字元(即與0x20-0x7E範圍內的字節相鄰的0位元組,還有CR和LF的0x0A和0x0D)來猜測該文本是否為UTF-16及其位元組順序。大量的(即遠遠高於隨機)相同的順序是UTF-16的一個非常好的指示,而0是在偶數還是奇數位元組中表明了位元組的順序。然而,這依然可能會導致假陽性和假陰性。

Unicode標準的一致性條款D98(第3.10節)規定:「UTF-16編碼方案可以以BOM開始,也可以不以BOM開始。然而,當沒有BOM時,在沒有高層協議的情況下,UTF-16編碼方案的位元組順序是大端序。」是否有更高層次的協議是可以解釋的。例如,在一台本地位元組順序為小端序的電腦上的文件,可能被默認為是以UTF-16LE編碼。因此,大端序的推定被廣泛地忽略了。在HTML5中使用的W3C/WHATWG編碼標準規定,標記為「utf-16」或「utf-16le」的內容將被解釋為小端序,「以處理部署的內容」[10]。然而,如果出現了位元組順序記號,那麼該記號將被視為「比其他任何東西都更有權威性」[11]

將UTF-16解釋為基於位元組的編碼的程式可能會顯示出亂七八糟的字元,但是ASCII字元會被識別出來,因為UTF-16表示的低字元與ASCII代碼相同,因此會顯示相同的字元。0的上字元可以顯示為無、空白、句號,或其他一些不變的字形。

UTF-32[編輯]

雖然位元組順序記號亦可以用於UTF-32,但這個編碼很少用於傳輸,其規則如同UTF-16

小端序UTF-32的BOM等同小端序UTF-16的BOM圖案後面加上一個NUL字元,這是一個不尋常的例子,即BOM在兩種不同的編碼中是相同的形式。使用BOM來識別編碼的程序員必須分辨文件是UTF-32編碼還是單純以NUL作為第一個字元。

不同編碼的位元組順序記號的表示[編輯]

編碼 表示(十六進位 表示(十進位
UTF-8 EF BB BF 239 187 191
UTF-16大端序 FE FF 254 255
UTF-16小端序 FF FE 255 254
UTF-32(大端序) 00 00 FE FF 0 0 254 255
UTF-32(小端序) FF FE 00 00 255 254 0 0
UTF-7 2B 2F 76和以下的一個位元組:[ 38 | 39 | 2B | 2F ] 43 47 118和以下的一個位元組:[ 56 | 57 | 43 | 47 ]
UTF-1 F7 64 4C 247 100 76
UTF-EBCDIC英語UTF-EBCDIC DD 73 66 73 221 115 102 115
Unicode標準壓縮方案英語Standard Compression Scheme for Unicode 0E FE FF 14 254 255
BOCU-1英語Binary_Ordered_Compression_for_Unicode FB EE 28 及可能跟隨著FF 251 238 40 及可能跟隨著255
GB-18030 84 31 95 33 132 49 149 51

另見[編輯]

參考文獻[編輯]

  1. ^ FAQ - UTF-8, UTF-16, UTF-32 & BOM. Unicode.org. [2017-01-28]. (原始內容存檔於2021-05-02). 
  2. ^ The Unicode® Standard Version 9.0 (PDF). The Unicode Consortium. [2021-06-16]. (原始內容存檔 (PDF)於2021-05-07). 
  3. ^ The Unicode Standard 5.0, Chapter 2:General Structure (PDF): 36. [2009-03-29]. (原始內容存檔 (PDF)於2021-04-22). Table 2-4. The Seven Unicode Encoding Schemes 
  4. ^ The Unicode Standard 5.0, Chapter 2:General Structure (PDF): 36. [2008-11-30]. (原始內容存檔 (PDF)於2021-04-22). Use of a BOM is neither required nor recommended for UTF-8, but may be encountered in contexts where UTF-8 data is converted from other encoding forms that use a BOM or where the BOM is used as a UTF-8 signature 
  5. ^ FAQ - UTF-8, UTF-16, UTF-32 & BOM: Can a UTF-8 data stream contain the BOM character (in UTF-8 form)? If yes, then can I still assume the remaining UTF-8 bytes are in big-endian order?. [2008-03-29]. (原始內容存檔於2012-09-01). 
  6. ^ Re: pre-HTML5 and the BOM from Asmus Freytag on 2012-07-13 (Unicode Mail List Archive). Unicode.org. [2012-07-14]. (原始內容存檔於2019-06-16). 
  7. ^ Bug ID: JDK-6378911 UTF-8 decoder handling of byte-order mark has changed. Bugs.sun.com. [2017-01-28]. (原始內容存檔於2017-12-19). 
  8. ^ Yergeau, Francois. UTF-8, a transformation format of ISO 10646. IETF. November 2003 [May 15, 2014]. RFC 3629. 
  9. ^ Alf P. Steinbach. Unicode part 1: Windows console i/o approaches. 2011 [24 March 2012]. (原始內容存檔於2012-03-22). However, since the C++ source code was encoded as UTF-8 without BOM (as is usual in Linux), the Visual C++ compiler erroneously assumed that the source code was encoded as Windows ANSI. 
  10. ^ UTF-16LE. Encoding Standard. WHATWG. [2021-06-17]. (原始內容存檔於2015-02-04). 
  11. ^ Decode. Encoding Standard. WHATWG. [2021-06-17]. (原始內容存檔於2015-02-04). 

外部連結[編輯]