網(wǎng)上也有許多關(guān)于純文本的討論,如果在搜索“亂碼”,更是不盡其數(shù)。如果你開始命令行,開始編碼,開始數(shù)據(jù)分析,開始操作中文,存文本及其字符編碼便是最基礎(chǔ)的東西。而往往基礎(chǔ)的東西,真正弄懂更為不易,而或者你已經(jīng)有了多年相關(guān)的經(jīng)驗(yàn),也不一定搞清楚了。
存文本由可打印字符組成,人可以直接閱讀和理解其形式。
純文本并非意味著文本是無結(jié)構(gòu)的,HTML、SGML、XML等都是有良好結(jié)構(gòu)定義的存文本,與直接的二進(jìn)制編碼相比,純文本所處的層面往往更高。大多數(shù)二進(jìn)制格式的問題在于,理解數(shù)據(jù)所必須的語境與數(shù)據(jù)本身是分離的,沒有應(yīng)用邏輯對其進(jìn)行解釋,這些數(shù)據(jù)絕對沒有意義,但是通過存文本,可以獲得自描述的、不依賴創(chuàng)建它的應(yīng)用的數(shù)據(jù)流。對于大多數(shù)二進(jìn)制文件,要成功的進(jìn)行解析,你必須了解整個格式的所有細(xì)節(jié)。
計算機(jī)的一切,到底都是二進(jìn)制的,所以文本文件是一種特殊的二進(jìn)制文件,特殊在于這些二進(jìn)制都對應(yīng)字符編碼,可以容易的進(jìn)行各種操作。
——2013年5月15日
最重要或者最難理解的就是其編碼格式,計算機(jī)中最小的操作單位是字節(jié)(Byte),通常每8位(bit)組成一個字節(jié),1KB=1024Byte=1024*8bit,二進(jìn)制也就是由0和1組成的串,為了書寫或者表示的方便,通常用16進(jìn)制來表示二進(jìn)制,如下表格:
0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
8 | 9 | A | B | C | D | E | F |
一個字節(jié)可以用兩位的十六進(jìn)制表示,00~FF,共256位0~255。下表是二進(jìn)制的位數(shù),可以表示的字符數(shù)目。
2^0 | 2^1 | 2^2 | 2^3 | 2^4 | 2^5 | 2^6 | 2^7 | 2^8 | 2^9 | 2^10 |
0 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 |
二進(jìn)制如何表示字符,也就是編碼格式標(biāo)準(zhǔn)制定的緣由??偟膩碇v,編碼可以分為兩類:
Unicode is a computing industry standard for the consistent encoding, representation and handling of text expressed in most of the world’s writing systems.
在表示一個Unicode的字符時,通常會用“U+”然后緊接著一組十六進(jìn)制的數(shù)字來表示這一個字符。Unicode的實(shí)現(xiàn)方式不同于編碼方式。一個字符的Unicode編碼是確定的。但是在實(shí)際傳輸過程中,由于不同系統(tǒng)平臺的設(shè)計不一定一致,以及出于節(jié)省空間的目的,對Unicode編碼的實(shí)現(xiàn)方式有所不同。Unicode的實(shí)現(xiàn)方式稱為Unicode轉(zhuǎn)換格式(Unicode Transformation Format,簡稱為UTF)。
目前通用的實(shí)現(xiàn)方式是UTF-16小端序(LE)、UTF-16大端序(BE)和UTF-8。在Windows 附帶的記事本(Notepad)中,“另存為”對話框可以選擇的四種編碼方式除去非Unicode編碼的ANSI(對于英文系統(tǒng)即ASCII編碼,中文系統(tǒng)則為GB2312或Big5編碼) 外,其余三種為“Unicode”(對應(yīng)UTF-16 LE)、“Unicode big endian”(對應(yīng)UTF-16 BE)和“UTF-8”。
UTF-8是UNICODE的一種變長字符編碼,由Ken Thompson于1992年創(chuàng)建?,F(xiàn)在已經(jīng)標(biāo)準(zhǔn)化為RFC 3629。UTF-8用1到6個字節(jié)編碼UNICODE字符。
從Unicode到UTF-8的編碼方式如下:
Unicode編碼(16進(jìn)制) | UTF-8 字節(jié)流(二進(jìn)制) |
000000 – 00007F | 0xxxxxxx |
000080 – 0007FF | 110xxxxx 10xxxxxx |
000800 – 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
010000 – 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-8的特點(diǎn)是對不同范圍的字符使用不同長度的編碼。對于0×00-0x7F之間的字符,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個字節(jié)。從上表可以看出,4字節(jié)模板有21個x,即可以容納21位二進(jìn)制數(shù)字。Unicode的最大碼位0x10FFFF也只有21位。
例如:“漢”字的Unicode編碼是0x6C49。0x6C49在0×0800-0xFFFF之間,使用用3字節(jié) 模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進(jìn)制是:0110 1100 0100 1001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
對于ANSI編碼方式,存在不同的字符集(Charset), 要正確解析一個ANSI字符串,還要選擇正確的字符集,每個字符集都有一個唯一的編號,稱為代碼頁(Code Page)。簡體中文(GB2312)的代碼頁為936,而系統(tǒng)默認(rèn)字符集的代碼頁為0,它表示根據(jù)系統(tǒng)的語言設(shè)置來選擇一個合適的字符集。
漢字編碼中現(xiàn)在主要用到的有三類,包括GBK,GB2312和Big5。
R.C. GB Uni. UTF-8 R.C. GB Uni. UTF-8 1601 啊 B0A1 554A E5958A 1602 阿 B0A2 963F E998BF 1603 埃 B0A3 57C3 E59F83 1604 挨 B0A4 6328 E68CA8 1605 哎 B0A5 54CE E5938E 1606 唉 B0A6 5509 E59489 1607 哀 B0A7 54C0 E59380 1608 皚 B0A8 7691 E79A91 1609 癌 B0A9 764C E7998C 1610 藹 B0AA 853C E894BC 1611 矮 B0AB 77EE E79FAE 1612 艾 B0AC 827E E889BE 1613 礙 B0AD 788D E7A28D 1614 愛 B0AE 7231 E788B1
ASCII
ASCII使用一個字節(jié)的其中7位二進(jìn)制數(shù)來表示所有的大寫和小寫字母,數(shù)字0 到9、標(biāo)點(diǎn)符號, 以及在美式英語中使用的特殊控制字符。
如前所述,每種編碼都有一種規(guī)范,如果按照編碼方式,能將其全部讀為字符串,就是文本文件。由于編碼方式的差異,程序是很容易通過判斷,來知道其編碼方式,如果都不行,那就是二進(jìn)制了。
另外還有一種方式,BOM,Windows就是使用BOM來標(biāo)記文本文件的編碼方式的操作系統(tǒng)。什么是BOM, w3.org 標(biāo)準(zhǔn) FAQ 中對此問題有一個專門的描述:http://www.w3.org/International/questions/qa-utf8-bom,具體如下:
在UCS 編碼中有一個叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實(shí)際傳輸中。UCS規(guī)范建議我們在傳輸字節(jié)流前,先傳輸 字符”ZERO WIDTH NO-BREAK SPACE”。這樣如果接收者收到FEFF,就表明這個字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個字節(jié)流是Little- Endian的。因此字符”ZERO WIDTH NO-BREAK SPACE”又被稱作BOM。
UTF-8不需要BOM來表明字節(jié)順序,但可以用BOM來表明編碼方式。字符”ZERO WIDTH NO-BREAK SPACE”的UTF-8編碼是EF BB BF。所以如果接收者收到以EF BB BF開頭的字節(jié)流,就知道這是UTF-8編碼了。
各種系統(tǒng)、工具,對于BOM處理也不一樣: