一篇文章帶你讀懂編碼!這下知道為什麼亂碼了吧。

前幾天有個同學問我:“老師,為什麼我按著別的文檔寫的一模一樣的,但我卻是亂碼呢?”

其實很簡單,因為你的編碼跟和人家不一樣!

我們電腦中編碼一般分為五種:

1.ANSI

2.UTF-16LE

3.UTF-16BE

4.UTF-8

5.帶有BOM的UTF-8

UTF-16BE、UTF-16LE、UTF-16 三者之間的區別

UTF-16BE,其後綴是 BE 即 big-endian,大端的意思。大端就是將高位的字節放在低地址表示。

UTF-16LE,其後綴是 LE 即 little-endian,小端的意思。小端就是將高位的字節放在高地址表示。

UTF-16,沒有指定後綴,即不知道其是大小端,所以其開始的兩個字節表示該字節數組是大端還是小端。即FE FF表示大端,FF FE表示小端。

一篇文章帶你讀懂編碼!這下知道為什麼亂碼了吧。

一、ANSI

ANSI(American National Standards Institute),中文:美國國家標準學會。

為使計算機支持更多語言,通常使用 0x80~0xFF 範圍的多個字節來表示 1 個字符。比如:漢字 '中' 在簡體中文Windows操作系統中,使用 [0xD6,0xD0] 這兩個字節存儲。對於ANSI編碼而言,0x00~0x7F之間的字符,依舊是1個字節代表1個字符。這一點是ANSI編碼與UTF-16編碼之間最大也最明顯的區別。比如"A君是第131號",在ANSI編碼中,佔用12個字節,而在UTF-16編碼中,佔用16個字節。因為A和1、3、1這4個字符,在ANSI編碼中只各佔1個字節,而在UTF-16編碼中,是需要各佔2個字節的。

記事本默認是以ANSI編碼保存文本文檔的,而正是這種編碼存在的bug招致了上述怪現象。假如保存時選擇Unicode、Unicode (Big Endian)、UTF-8編碼,就正常了。此外,假如以ANSI編碼保存含有某些特別符號的文本文檔,再次打開後符號也會變成英文問號。

  • 特點0x80~0xFF 多個字節來表示
  • bug重新打開時將是亂碼
  • 二、UTF-16LE,UTF-16BE

    Unicode 是 unicode.org 制定的編碼標準,目前得到了絕大部分操作系統和編程語言的支持。unicode.org 官方對 Unicode 的定義是:Unicode provides a unique number for every character, no matter what the platform, no matter what the program, no matter what the language。可見,Unicode 所做的是為每個字符定義了一個相應的數字表示。比如,“a”的 Unicode 值是 0x0061,“一”的 Unicode 值是 0x4E00,這是最簡單的情況,每個字符用2個字節表示。

    unicode.org 定義了百萬個以上的字符,如果將所有的字符用統一的格式表示,需要的是 4 個字節。“a”的 Unicode 表示就會變成 0x00000061,而“一“的 Unicode 值是 0x00004E00。實際上,這就是 UTF32,Linux 操作系統上所使用的 Unicode 方案。

    但是,仔細分析可以發現,其實絕大部分字符只使用 2 個字節就可以表示了。英文的 Unicode 範圍是 0x0000-0x007F,中文的 Unicode 範圍是 0x4E00-0x9F**,真正需要擴展到 4 個字節來表示的字符少之又少,所以有些系統直接使用 2 個字節來表示 Unicode。比如 Windows 系統上,Unicode 就是兩個字節的。對於那些需要 4 個字節才能表示的字符,使用一種代理的手法來擴展(其實就是在低兩個字節上做一個標記,表示這是一個代理,需要連接上隨後的兩個字節,才能組成一個字符)。這樣的好處是大量的節約了存取空間,也提高了處理的速度。這種 Unicode 表示方法就是 UTF16。一般在 Windows 平臺上,提到 Unicode,那就是指 UTF16 了。

    至於 UTF16-LE 和 UTF16-BE,則與計算機的 CPU 構架有關。LE 指 Little Endian,而 BE 指 Big Endian。由於 UTF16 是雙字節編碼,所以兩個字節保存時哪個在前,哪個在後關係到解析出字符的結果。至於為什麼會出現 BE 和 LE 的編碼,則是由於歷史原因造成的:在 Mac 和 PC 機上,對字節順序的理解是不一致的。如果一個文件不明確說明 UTF16 使用的是 BE 還是 LE,那麼就需要通過 BOM 來指明瞭。我們一般的 X86 系統都是 Little Endian 的,可以認為 UTF16=UTF16-LE。

    四、UTF-8

    由於對於歐洲和北美,實際上使用的編碼範圍在 0x0000-0x00FF 之間,只需要一個字符就可以表示所有的字符。即使是使用 UTF16 來作為內存的存取方式,還是會帶來巨大的空間浪費,因此就有了 UTF8 的編碼方式。UTF8 是一個可變長度字符編碼,它同時是一個前綴碼,前綴碼的特徵是,編碼系統中的任意一個合法的碼不會是另外一個碼的前綴,所以 UTF8 不需要指定字節序。一個 UTF8 編碼可以用 1~6 個字節來表示,將第一個字節的前幾個比特設置為 1 來指定這個字符佔用幾個比特,比如一個兩字節的字符的編碼,第一位是 110xxxxx,第二位是 10xxxxxx,而一個六字節字符的編碼是這樣的:1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx,所以 UTF-8 最多能編碼 231 個字符。所以對於只需要1個字節的字符,就使用一個字節。對於中日韓等原本需要兩個字節才能表示的字符,則通過一個UTF16-UTF8 的算法實現相互之間的轉換,一般需要 3 個字節才能表示。UTF8 使用的算法很有意思,大致映射關係如下:

    Unicode編碼UTF-8編碼(二進制)U+0000 – U+007F0xxxxxxxU+0080 – U+07FF110xxxxx 10xxxxxxU+0800 – U+FFFF1110xxxx 10xxxxxx 10xxxxxxU+10000 – U+10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

    由於 UTF8 可以方便的轉換為 UTF16 和 UTF32,而且 UTF8 在每個操作系統平臺上的實現都是一樣的,也不存在跨平臺的問題,所以 UTF8 成為跨平臺的 Unicode 很好的解決方案。當然,對於中文來說,由於每個字符需要 3 個字節才能表示,還是有點浪費的。

    5.帶有BOM的UTF-8

    UTF-8 不需要 BOM,儘管 Unicode 標準允許在 UTF-8 中使用 BOM。
    所以不含 BOM 的 UTF-8 才是標準形式

    你下載的模板編碼很多都是帶BOM的UTM-8,只需要改下你的編碼就可以了。

    最後,小編想說:我是一名python開發工程師,

    整理了一套最新的python系統學習教程,

    想要這些資料的可以關注私信小編“01”即可(免費分享哦)希望能對你有所幫助


    分享到:


    相關文章: