聊一聊BOM

最近在看Node源碼的時候,偶然間,看到如下函數:

/**
 * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
 * because the buffer-to-string conversion in `fs.readFileSync()`
 * translates it to FEFF, the UTF-16 BOM.
 */
function stripBOM(content) {
  if (content.charCodeAt(0) === 0xFEFF) {
    content = content.slice(1);
  }
  return content;
}

對於函數的功能,註釋寫的很清楚了-用於清除字節序標識符(BOM)。

對於BOM,相信大多數人對其即陌生又熟悉,我們在各大IDE中常常見到它的身影,但要真的把它解釋清除,卻有點力不從心。故此,筆者利用閒暇之餘搜索資料整理成文,如果錯漏,還望提點!

字節序

在解釋BOM之前,我們不得不提到字節序。

在古時,我們的很多書刊保有從左到右的排版的習慣。即使是今天,某些國家的文字讀序依舊存在差異。計算機世界也是如此。

我們把多字節排練的順序叫做字節序。

這裏我們通過一個例子展開說明(本例來自:“字節序”是個什麼鬼?):

給定兩個分別需要4個字節存儲的整數,爲了方便說明,使用16進製表示這兩個數,即0x12345678和0x11223344。對於如何存儲,有人提了兩個方案:

方案一:

image

方案二:

image

對於方案一,高位字節在存儲在高位地址,低位字節在低位地址,我們稱之爲大端(Big endian)字節序。方案二把低位字節在前,高位字節在後,我們把這種順序叫做小端(Little endian)字節序。

BOM

對於人類而言,字節序也許並不是問題。比如從右往左讀"字節序",聰明如你們,會發現“序節字”根本語義不通,可以輕鬆的找到解決之道。但對於計算機而言,它不明白什麼是語義,也沒法聯繫上下文。它只能按照給定的指令去讀取字節。如果是大端字節序,先讀到的就是高位字節,後讀到的就是低位字節。小端字節序正好相反。

所以對於計算機而言,我們需要一種方法去標識字節序,以防亂碼的出現。BOM就是一種用於標識的unicode字符,它常被用來當做標示以UTF-8、UTF-16或UTF-32爲編碼的文件

對於UTF-16和UTF-32而言,因爲他們分別使用2個字節和4個字節編碼Unicode字符,對於多字節編碼,BOM的存在顯然很有必要。此時BOM被放置爲文件或字符串流的第一個字符,如果標識符爲U+FFFE則表示大端字節序,如果標識符爲U+FEFF則表示小端字節序。

那既然BOM是用於標示字節序的,那爲什麼還要把它刪除呢?這裏就不得不提一下UTF-8了。

UTF-8是一種可變字節長度的編碼方式(最小1字節,最大4字節),也就是說UTF-8可以根據數據大小來決定要存儲的字節數。它的編碼方式與其他兩者不同,無需使用BOM。

UTF-8在首字節標識了字節的個數。如果首字節以0開頭,則代表單字節編碼,如果以110開頭者表示該字節爲兩個字節中的第一個字節,以此類推。除了單字節外,多字節UTF-8碼的後續字節均以10開頭。

所以1~4字節UTF-8編碼看起來是這樣的:

0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

So BOM 在UTF-8編碼中是非必須的,在類Unix系統(大量使用文本文件,用於文件格式,用於進程間通信)中,這種做法(插入BOM)是不被建議採用,因爲它會妨礙到如解譯器腳本開頭的Shebang等的正確處理,但是許多視窗程序(包含記事本)會需要添加字節順序標記到UTF-8文件。

參考

  1. “字節序”是個什麼鬼?
  2. 爲什麼UTF-8沒有字節序問題?
  3. Unicode字符集與UTF-8編碼
  4. 字節順序標記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章