端序記號

端序記號，或稱位元組順序記號（byte-order mark，BOM）是位於碼點`U+FEFF`的統一碼字符的名稱。當以UTF-16或UTF-32來將UCS/統一碼字符所組成的字串編碼時，這個字符被用來標示其端序。它也被用來當做標示文件是以UTF-8、UTF-16或UTF-32編碼的記號。

端序記號通常有幾種涵義：

- 在16位元和32位元的情況下，文字流的端序。
- 表示文字流非常有可能是統一碼編碼。
- 使用的是哪一種統一碼字元編碼。

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

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

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

## 使用

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

### UTF-8

雖然在統一碼標準中，允許UTF-8也中使用端序記號，但實際上並不一定需要。UTF-8編碼過的端序記號則被用來標示它是UTF-8的文件。它只用來標示一個UTF-8的檔案，而不用來說明端序。但同時，該標準也不建議在有端序記號的情況下將其刪除，以便在不同的編碼之間轉換時不會丟失資訊，並讓依賴端序記號的程式能順利運作。IETF建議，如果一個協議(a)總是使用UTF-8，或者(b)有一些其他方法來表明正在使用的編碼，那麼它「應該禁止使用U+FEFF作為簽名」。

許多視窗程式（包含記事本）會需要添加端序記號到UTF-8檔案，否則將無法正確解析編碼，而出現亂碼。然而，在類Unix系統（大量使用文本文件，用於檔案格式，用於行程間通訊）中，這種做法則不被建議採用。因為它會妨礙到如解譯器腳本開頭的Shebang等的一些重要的碼的正確處理。它亦會影響到無法識別它的程式語言。如gcc會報告源碼檔開頭有無法識別的字符。而在PHP中，如果沒有啟用輸出緩衝（output buffering），它會使得頁面內容開始被送往瀏覽器（即：使用者標頭檔已被送出），這使PHP腳本無法指定使用者標頭檔（HTTP Header）。端序記號在UTF-8中被表示為序列`0xEF 0xBB 0xBF`，對大部分未準備好處理UTF-8的文本編輯器及網頁瀏覽器而言，在ISO-8859-1的環境中則會顯示`ï»¿`。

統一碼標準允許在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。

另一方面，微軟的編譯器和解釋器，以及許多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`的碼位被保證將不會被指定成一個統一碼字元。這意味著`0xFF`、`0xFE`將只能被解釋成小端序中的`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」的內容將被解釋為小端序，「以處理部署的內容」。然而，如果出現了端序記號，那麼該記號將被視為「比其他任何東西都更有權威性」。

將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｜`DD 73 66 73`｜`221 115 102 115`

統一碼標準壓縮方案｜`0E FE FF`｜`14 254 255`

統一碼二進制有序壓縮｜`FB EE 28` 及可能跟隨著`FF`｜`251 238 40` 及可能跟隨著`255`

GB-18030｜`84 31 95 33`｜`132 49 149 51`

## 外部連結

- Unicode FAQ: UTF-8, UTF-16, UTF-32 & BOM
- The Unicode Standard, chapter 2.6 Encoding Schemes
- The Unicode Standard, chapter 2.13 Special Characters and Noncharacters, section Byte Order Mark（BOM）
- The Unicode Standard, chapter 16.8 Specials, section Byte Order Mark (BOM): U+FEFF