文本編碼

文本編碼

  • 文本編碼這個問題自三年前就困擾着我,當時是用Python處理多國語言時出現的bug,最後問題解決了,但其中具體邏輯並不懂。後來零零散散接觸了不少資料,算是大致弄明白,記錄如下。

unicode與ascii等編碼方案

ascii

  • ascii編碼方案一共規定了128個字符對應的二進制表示,只佔用了一個字節的後面7bit,最高位爲0
  • 歐洲國家使用128個符號不足以表示所有字母,使用了最高位。因此不同的國家128~255表示不同的符號,並不通用,即爲擴展的ascii碼,包括ISO-8859-1~15。這些都是單個字節編碼。
  • ISO-8859-1
    • ISO-8859-1收錄的字符除ASCII收錄的字符外,還包括西歐語言、希臘語、泰語、阿拉伯語、希伯來語對應的文字符號。歐元符號出現的比較晚,沒有被收錄在ISO-8859-1當中
    • ISO-8859-1編碼範圍使用了單字節內的所有空間,在支持ISO-8859-1的系統中傳輸和存儲其他任何編碼的字節流都不會被拋棄
    • Latin1是ISO-8859-1的別名,有些環境下寫作Latin-1

gb2312

  • 一種雙字節編碼,包含6763個漢字

gbk

  • 對gb2312的擴展,可以表示21003個漢字,兼容gb2312

gb18030

  • unicode的一種天朝實現
  • 採用單、雙、四字節編碼,兼容gb2312

base64

  • base64使用64個可打印字符表示二進制數據。每個單元包含6bit。轉換後每76個單元要加上一個換行符。
  • 可打印字符包括:A-Z a-z 0-9以及兩個其他不定符號,大部分實現爲+ /
  • 將每3個字符編碼爲4個單元,不足3個的用=補足

unicode

  • unicode試圖表示所有的字符
  • 採用unicode的系統、平臺有:
    • windows NT及後續系統、java採用utf16作爲內置編碼
    • .net, mac, kde同樣使用unicode
    • utf-8是unix-like操作系統的主要存儲編碼方案
    • utf-8是html文件最常用的unicode編碼
    • XML及其子集XHTML採用UTF-8作爲標準字集
  • 編碼方案
    • 對每個字符規定了一個碼點:code point
    • unicode現在包括17個平面,每個平面最多可以存放65536個字符,也即需要至少21個bit才足夠表示所有碼點。17個平面的碼位可表示爲從U+xx0000到U+xxFFFF,其中xx表示十六進制值從0016到1016,共計17個平面
    • 首先的256個字符編碼與ISO-8859-1相同
    • 表示方式爲U+緊跟十六進制表示。基本平面(BMP U+0000到U+FFFF)中採用四個數字(2byte),16個輔助平面(SMP U+10000到U+10FFFF)中採用5~6個數字
  • 實現方案
    • 實現方案包括Unicode Transformation Format (UTF)和Universal Coded Character Set (UCS)兩種
    • unicode的實現方式稱爲Unicode轉換格式(Unicode Transformation Format,簡稱爲UTF)
    • utf8:8bit變長編碼,詳細實現見下一節
    • utf16:16bit變長編碼,下有詳述
    • utf32:32bit定長編碼,完全對應unicode
    • usc-2:2byte定長編碼,utf16的子集,JavaScript使用此編碼方案。因爲不能表示更多字符,後續在此基礎上發展出了utf16
    • usc-4:等價於utf32
    • gb18030
  • utf16
    • 對BMP中的字符使用2byte表示,SMP使用4byte
    • BMP從U+D800到U+DFFF之間的碼位區段是永久保留不映射到Unicode字符
    • 輔助平面的字符位共有2^20個,也就是說,對應這些字符至少需要20個二進制位。UTF-16將這20位拆成兩半,前10位映射在U+D800到U+DBFF(空間大小2^10),稱爲高位(H),後10位映射在U+DC00到U+DFFF(空間大小2^10),稱爲低位(L)。這意味着,一個輔助平面的字符,被拆成兩個基本平面的字符表示。
    • 對於兩個字節,發現它的碼點在U+D800到U+DBFF之間,就可以斷定,緊跟在後面的兩個字節的碼點,應該在U+DC00到U+DFFF之間,這四個字節必須放在一起解讀。

utf8

  • 採用1~4個byte對unicode進行編碼,每個字元只有1byte,不存在字節序問題
  • unicode和utf8編碼對應關係

      0000 0000-0000 007F | 0xxxxxxx
      0000 0080-0000 07FF | 110xxxxx 10xxxxxx
      0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
      0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    • 單字節字符的最高有效比特永遠爲0。
    • 多字節序列中的首個字元組的幾個最高有效比特決定了序列的長度。最高有效位爲110的是2字節序列,而1110的是三字節序列,如此類推。
    • 多字節序列中其餘的字節中的首兩個最高有效比特爲10
    • 具體爲何根據這樣麻煩的規則編碼呢?一是防止解碼出現歧義,二是儘量壓縮存儲空間。如果學過編碼理論或者信息論應當很容易明白。
  • 相對於utf16
    • utf16編碼效率/性能較高,字符到字節轉換更爲方便
    • utf8消耗存儲空間較少

文本和IO

  • IO時經常需要對文本進行編解碼或編碼格式轉化
  • 在硬盤文件中:以文件編碼格式存儲
  • 在內存中:java和c#用utf16
  • 如何顯示在屏幕上:顯卡驅動(虛擬設備)根據輸入字節及編碼渲染
  • 網絡:按照應用層商定的協議編解碼

utf8和BOM

什麼是BOM

  • BOM(byte order mark)是爲 UTF-16 和 UTF-32 準備的,用於標記字節序(byte order)。
  • utf不同編碼實現的BOM定義:
    • UTF-8 EF BB BF
    • UTF-16(大端序) FE FF
    • UTF-16(小端序) FF FE
    • UTF-32(大端序) 00 00 FE FF
    • UTF-32(小端序) FF FE 00 00
  • 對於utf8,沒有字節順序的議題。UTF-8編碼過的字節順序標記則被用來標示它是UTF-8的文件。它只用來標示一個UTF-8的文件,而不用來說明字節順序。
  • 對於utf16和utf32,用來表示大端還是小段
  • BOM相當於魔數(magic number)
    • 圖像文件、ELF文件、class文件都存在魔數
    • linux命令file能根據魔數(libmagic)判斷文件類型
    • 文件擴展名更重要的作用是讓系統決定當用戶想打開這個文件的時候用哪種軟件運行,如Windows系統中exe文件是可執行檔,doc文件默認用Microsoft Word打開的Word文件。

記事本四種另存爲的編碼格式

  • ANSI(對於英文系統即ASCII編碼,中文系統則爲GB2312或Big5編碼)
  • “Unicode”(對應UTF-16 LE)
  • “Unicode big endian”(對應UTF-16 BE)
  • “UTF-8”:帶 BOM 的 UTF-8

使用utf8不要包含BOM

  • 不含 BOM 的 UTF-8 纔是標準形式,在 UTF-8 文件中放置 BOM 主要是微軟的習慣(順便提一下:把帶有 BOM 的小端序 UTF-16 稱作「Unicode」而又不詳細說明,這也是微軟的習慣)。微軟在 UTF-8 中使用 BOM 是因爲這樣可以把 UTF-8 和 ASCII 等編碼明確區分開,但這樣的文件在 Windows 之外的操作系統裏會帶來問題。
  • 許多windows程序(包含記事本)會添加字節順序標記到UTF-8文件。然而,在類Unix系統中,這種作法則不被建議採用。因爲它會妨礙到如shell腳本開頭的一些重要的碼的正確處理。它亦會影響到無法識別它的編程語言。

參考

wiki:BOM
wiki:Unicode

 
 

轉載請註明作者:Focustc,博客地址爲http://blog.csdn.net/caozhk,原文鏈接爲點擊打開

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章