Unicode和UTF-8/16到底是什麼關係

前因

一般程序讀取文件的時候,文件的內容都能準確被獲取,但有時候最前面會多出幾個奇怪的字符,直接打開文件卻什麼都看不到【哭的表情】,以下圖,運行程序時在「Java咖啡屋」前多了一個神奇的字符。 數組

上述問題其實是由於UTF-8的一些細節問題致使的,(固然這都能怪到坑爹的Windows身上)可能你們對UTF-8編碼、Unicode編碼都耳熟能詳,但對裏面的一些細節問題又說不上來,今天咱們就一塊兒來好好說道說道這些問題。 主要是

  1. 什麼是Unicode
  2. 爲何會有UTF-8,UTF-16
  3. 什麼是字節序(BOM, Byte Order Mark)

1. 什麼是Unicode

維基百科的解釋是網絡

Unicode是計算機科學領域裏的一項業界標準。它對世界上大部分的文字系統進行了整理、編碼,使得計算機能夠用更爲簡單的方式來呈現和處理文字。編碼

這就是說Unicode對大多數文字都進行了編碼,基本上每個字符都能在Unicode找到對應的編碼,這樣全球人民都只承認一個標準就夠了,這就是Unicode。3d

Unicode有UCS-2和UCS-4之分,UCS-2只有2個字節,16位,最多表示65536個字符,其中中文字符佔了20000多個(我國文字在Unicode裏佔了大頭,可喜可賀),其編碼從4E00到9FA5,例如「嚴」=4E25, 「贇」=8D5Fcode

可是6萬多個字符還不足以表示全世界的文字(但經常使用的已經足夠了),所以推出了UCS-4這種4字節編碼,做爲UCS-2的子集。 另外,在Java內存中老是以UCS-2進行編碼,String的length()方法也是以字符爲單位,經常使用中文字符長度爲1,生僻字(UCS-4才能編碼的)的長度是2. cdn

所以判斷字符串是否包含 經常使用中文字符,只需判斷其字符編碼是否在4E00到9FA5之間便可。

2. 爲何會有UTF-八、UTF-16

Unicode只規定了字符該如何編碼,但並無定義編碼後該如何存儲。例如「嚴」的Unicode編碼是4E25,同時「N」的編碼是4E,「%」的編碼是25,那麼計算機看到4E25到底是「嚴」仍是「N%」呢,UTF-八、UTF-16就是用來解決這個問題。blog

維基百科對UTF-8的解釋是內存

UTF-8是一種針對Unicode的可變長度字符編碼,也是一種前綴碼。它能夠用來表示Unicode標準中的任何字符,且其編碼中的第一個字節仍與ASCII兼容,這使得原來處理ASCII字符的軟件無須或只須作少部分修改,便可繼續使用。所以,它逐漸成爲電子郵件、網頁及其餘存儲或發送文字優先採用的編碼。字符串

例如「N」的Unicode編碼是4E(0100 1110),屬於0000~007F,所以它的UTF-8仍是4E(0100 1100),同理「%」的Unicode編碼和UTF-8編碼都是25。按照UTF-8的規範,ASCII在UTF-8下的編碼沒有變化。get

「嚴」的Unicode編碼是4E25(0100 1110 0010 0101),屬於0800~FFFF內,所以它的UTF-8編碼是E4B8A5(1110 0100 10111000 10100101,粗體部分就是Unicode編碼)。因此會出現中文字符在UTF-8編碼下佔用了3個字節存儲空間的現象。

要注意的是,若是中文字符的編碼超出了0800~FFFF的範圍,就像表中的最後一行,這些中文字符都是生僻字,會佔用4個字節的存儲空間。

所以,UTF-8是一種變長的存儲方式,對於N個字符的文本,根據字符的不一樣,存儲空間在N~4N不等。適合文本中大量ASCII字符的場景。

例如,Sting的getBytes()方法能夠返回不一樣編碼方式下的字節數組,「嚴」在UTF-8下佔3個字節,在GBK下佔2個字節。

UTF-16簡單理解就是UCS-2是什麼,UTF-16就存儲什麼。(這裏只說最簡單最通用的,我也不是特別清楚UTF-16的複雜狀況)。例如「Java咖啡屋」的UTF-16編碼

FEFF是字節序,下文詳細解釋。

004A = J
0061 = a
0076 = v
0061 = a
5469 = 咖
5561 = 啡
5C4B = 屋
咱們能夠看到UTF-16每個字符對應2個字節16位。
對於ASCII字符,高位補0,其他使用Unicode編碼。
對於經常使用中文字符,直接使用Unicode編碼。
所以UTF-16存儲ASCII的空間比UTF-8大,但存儲中文字符的空間比UTF-8小。

3. 什麼是字節序(BOM, Byte Order Mark)

計算機硬件存儲一個雙字節字符有兩種方式:

  • 高位字節在前,低位字節在後,稱爲大端字節序(big endian),也是人類習慣閱讀的方式。
  • 低位字節在前,高位字節在後,稱爲小端字節序(little endian)

爲何要搞出兩種字節序,統一不行嗎?

由於計算機電路先處理低位字節,效率比較高,由於計算都是從低位開始的。因此,計算機的內部處理都是小端字節序。

可是,人類仍是習慣讀寫大端字節序。因此,除了計算機的內部處理,其餘的場合幾乎都是大端字節序,好比網絡傳輸和文件儲存。 上文提到的FEFF是指大端字節序,若是以小端字節序存儲,以下圖,對比上圖的大端字節序都高低位顛倒了。

特別的,UTF-8是單字節編碼,因此字節序BOM對UTF-8來講沒有意義。

可是!!!Windows記事本有個很坑的地方,文件雖然以UTF-8存儲,可是仍是會在前面加入字節序FEFF,FEFF在UTF-8的編碼是EFBBBF,因此用記事本新建一個空文件保存爲UTF-8,會發現這個文件居然佔用3個字節,這就是UTF-8下的BOM。

再次回到文章一開始遇到的問題,那個神奇的字符就是BOM,只要將文件用notepad++或者sublime text等編輯軟件從新保存,就不會出現文中的問題了。

這告訴了咱們一個道理,珍惜生命,遠離記事本!遠離記事本!遠離記事本!

相關文章
相關標籤/搜索