1、UTF-8編碼方式正則表達式
1.算法
接下來將分別介紹Unicode字符集的三種編碼方式:UTF-八、UTF-1六、UTF-32。這裏先介紹應用最爲普遍的UTF-8。瀏覽器
爲知足基於ASCII、面向字節的字符處理的須要,Unicode標準中定義了UTF-8編碼方式。UTF-8應該是目前應用最普遍的一種Unicode編碼方式(但不是最先面世的,UTF-16要早於UTF-8面世)。它是一種使用8位碼元(即單字節碼元)的變寬(即變長或不定長)碼元序列的編碼方式。函數
因爲UTF-16對於ASCII字符也必須使用兩個字節(由於是16位碼元)進行編碼,存儲和處理效率相對低下,而且因爲ASCII字符通過UTF-16編碼後獲得的兩個字節,高字節始終是0x00,不少C語言的函數都將此字節視爲字符串末尾從而致使沒法正確解析文本。性能
所以,UTF-16一開始推出的時候就遭到不少西方國家的抵制,大大影響了Unicode的推行。因而後來又設計了UTF-8編碼方式,才解決了這些問題。編碼
2.url
UTF-8的碼元由8位單字節組成;在UTF-8中,由於碼元較小的緣故,Unicode碼點值被映射到一個、兩個、三個或四個碼元;換言之,UTF-8使用一個至四個8位單字節碼元的序列來表示Unicode字符。spa
UTF-8編碼方式對全部ASCII碼點值(0x00~0x7F)具備透明性。所謂透明性,具體指的是在U+0000到U+007F範圍內(十進制爲0~127)的Unicode碼點值,被直接轉換爲UTF-8單一字節碼元0x00~0x7F,與ASCII碼沒有區別。操作系統
而且,0x00~0x7F不會出如今UTF-8編碼的非ASCII字符的首字節與非首字節的任意一個字節中(非ASCII字符的UTF-8編碼爲由多個單字節碼元所組成的碼元序列),這樣就保證了與早已應用普遍且已成爲工業標準的ASCII碼的徹底兼容,避免了歧義,同時糾錯能力也強。設計
(笨笨阿林原創文章,轉載請註明出處)
3.
UTF-8同其餘的多字節碼元編碼方式相比具備如下優勢:
a) UTF-8的編碼空間足夠大,將來Unicode新標準收錄更多字符,UTF-8也能適應,所以不會再出現UTF-16那樣的尷尬。
(注:這裏所指的編碼空間並非前文所提到的編號空間Code Space,編號空間屬於編號字符集CCS裏的概念,而編碼空間屬於字符編碼方式CEF裏的概念,二者不能等同;這裏的編碼空間可理解爲編碼方式的將來可擴展性、高適應性,詳見後文《UTF-8到底是怎麼編碼的——UTF-8的編碼算法介紹》以及《UTF-16到底是怎麼編碼的——UTF-16的編碼算法介紹》)
b) UTF-8是變長編碼(準確地說是變長碼元序列,而碼元自己是固定長度爲8位單字節的,也就是說,UTF-8採用的單字節碼元),好比一個字節足以容納全部的ASCII字符,就用一個字節來存儲,沒必要在高位補0以浪費更多的字節來存儲,所以在英語做爲國際語言的現實狀況下,UTF-8因其ASCII字符的單字節編碼這一特性可節省空間。
c) UTF-8徹底直接兼容ASCII碼,而非不徹底間接兼容。
d) UTF-8的碼元序列的第一個字節指明瞭後面所跟的字節的數目(即帶有前綴碼),這對字節流的前向解析很是有效(詳見後文《UTF-8到底是怎麼編碼的——UTF-8的編碼算法介紹》)。
e) 也由於UTF-8編碼帶有前綴碼,因此容錯性好,即便在傳輸過程當中發生局部的字節錯誤,好比即使丟失、增長、改變了某些字節,也不會致使全部後續字符所有錯亂這樣傳遞性、連鎖性的錯誤問題(不然,若存在錯誤傳遞性、連鎖性的話,一旦中間某些字節出錯,則必須丟棄從出錯點開始到結尾的全部編碼字節,好比GB碼、UTF-32碼就是如此),所以很容易從新同步,具備很強的魯棒性(即健壯性)。
f) 因爲UTF-8編碼沒有狀態,從UTF-8字節流的任意位置開始能夠有效地找到一個字符的起始位置,字符邊界很容易界定、檢測出來,因此具備很好的「自同步性」。
g) UTF-8已經成爲互聯網所採用的字符編碼方式的事實標準。
h) UTF-8是字節順序無關的(由於是單字節碼元,而非像UTF-1六、UTF-32這樣的多字節碼元),它的字節順序在全部系統中都是同樣的,其碼元序列與字節序列相同,所以它實際上並不須要字節順序標記BOM(Byte-Orde Mark),雖然Windows系統常常「畫蛇添足」地加上BOM。(有關字節序標記BOM的介紹見下文)
字節序問題在進行信息交換時會帶來不小的麻煩。若是字節序未協商好,將致使亂碼;若協商結果爲雙方一個採用大端一個採用小端,則必然有一方要進行大小端轉換,性能損失不可避免(字節序的大小端問題其實不像看起來那麼簡單,有時會涉及硬件、操做系統、上層應用軟件多個層次,可能會致使屢次轉換,詳見前文中有關字節序Byte-Orde的介紹)。
i) 字節FE(二進制爲1111 1110)和FF(二進制爲1111 1111)在UTF-8編碼中永遠不會出現(由於UTF-8編碼方式中,每一個字節只能以0、1十、11十、11110或10開頭,詳見後文介紹)。所以能夠用稱之爲零寬度不中斷空格(ZERO WIDTH NO-BREAK SPACE)的字符(Unicode字符名稱爲U+FEFF)做爲字節順序標記BOM來標明UTF-16或UTF-32文本的字節序。
(Windows系統中BOM有時也用在UTF-8編碼的文本文件的開頭,雖然UTF-8編碼不存在字節序問題,但Windows卻用BOM來代表該文本文件的編碼格式爲UTF-8,看起來這有點「畫蛇添足」,其具體緣由詳見後文)
j) UTF-8編碼能夠經過屏蔽位和移位操做快速讀寫。
k) 字符串比較時strcmp()和wcscmp()的返回結果相同,所以使排序變得更加容易。
4.
UTF-8編碼方式也並不是天衣無縫,大體上有以下缺點:
a) 沒法根據字符數直接判斷出UTF-8文本的字節數,由於UTF-8是一種變長編碼方式(碼元雖然固定爲8位單字節,但碼元序列是變長的,多是單個碼元共8位,好比ASCII字符;也多是兩個碼元共16位、三個碼元共24位、四個碼元共32位等)。所以,不管是計算字符數,仍是執行索引操做,效率都不高。
b) 須要用2個字節編碼那些在擴展ASCII(即EASCII)字符集中只需1個字節編碼的擴展字符。
c) 以8位單字節碼元編碼的UTF-8字符會被Email網關過濾,由於Internet上的信息傳輸最初設計爲7位ASCII碼字符(ASCII僅用到了1個字節的低7位)的傳輸。所以產生了UTF-7編碼(相似於一樣爲Email傳輸而設計的Base64編碼或quoted-printable編碼,因爲Base64編碼或quoted-printable編碼各有其不足,所以又設計了UTF-7編碼)。
d) UTF-8在它的表示中使用值100xxxxx的概率超過50%,而現存的實現如ISO 202二、487三、6429和8859系統,會把它錯認爲是C1控制碼。所以產生了UTF-7.5編碼。
(笨笨阿林原創文章,轉載請註明出處)
2、字節序標記BOM
1.
在將邏輯形式的碼元序列(或可稱之爲邏輯編碼)映射爲物理形式的字節序列(或可稱之爲物理編碼)時,因系統平臺的差別,存在一個字節序(Byte-Order字節順序)的問題。Unicode/UCS規範中推薦的標記字節順序的方法是BOM字節序標記(Byte-Order Mark字節順序標記)。
字節序標記BOM是Unicode碼點值爲FEFF(十進制爲65279,二進制爲1111 1110 1111 1111)的字符的別名。
最初,字符U+FEFF若是出如今字節流的開頭,則用來標識該字節流的字節序——是高位在前仍是低位在前;若是它出如今字節流的中間,則表達爲該字符的原義——零寬度不中斷空格(ZERO WIDTH NO-BREAK SPACE零寬度無斷空白)。該字符名義上是個空格,其實是零寬度的,即至關因而不可見也不可打印字符(日常使用較多的是ASCII空格字符,是非零寬度的,須要佔用一個字符的寬度,爲可見不可打印字符)。
從Unicode 3.2開始,U+FEFF只能出如今字節流的開頭,且只能用於標識字節序,就如它的別名——字節序標記——所表示的意思同樣;除此之外的用法已被捨棄。取而代之的是,使用U+2060來表示零寬度不中斷空格。
2.
若是UTF-16編碼的字節序列爲大端序,則該字節序標記在字節流的開頭呈現爲0xFE 0xFF;若字節序列爲小端序,則該字節序標記在字節流的開頭呈現爲0xFF 0xFE。若是UTF-32編碼的字節序列爲大端序,則該字節序標記在字節流的開頭呈現爲0x00 0x00 0xFE 0xFF;若字節序列爲小端序,則該字節序標記在字節流的開頭呈現爲0xFF 0xFE 0x00 0x00。
UTF-8編碼自己沒有字節序的問題,但仍然有可能會用到BOM——有時被用來標示某文本是UTF-8編碼格式的文本;再強調一遍:在UFT-8編碼格式的文本中,若是添加了BOM,則只用它來標示該文本是由UTF-8編碼方式編碼的,而不用來講明字節序,由於UTF-8編碼不存在字節序問題。
3.
許多Windows程序(包含記事本)會添加BOM到UTF-8編碼格式的文件中(至於爲何要添加BOM,可參看後續《微軟跟聯通有仇?》一文)。然而,在類Unix系統中,這種做法則不被建議採用。
由於它會影響到沒法識別它的編程語言,如gcc會報告源碼文件開頭有沒法識別的字符;而在PHP中,若是沒有激活輸出緩衝(output buffering),它會使得頁面內容開始被送往瀏覽器(即header頭被提交),這使PHP腳本沒法指定header頭(HTTP Header)。
對於已在IANA註冊的字符編碼(這裏的字符編碼實際爲字符編碼模式CES)UTF-16BE、UTF-16LE、UTF-32BE和UTF-32LE等來講,不可以使用BOM。由於其名稱自己已決定了其字節順序。對於已註冊的字符編碼(這裏的字符編碼實際爲字符編碼方式CEF)UTF-16和UTF-32來講,則必須在文本開頭使用BOM。
4.
不一樣編碼的字節序列中所使用的字節序標記BOM自己的字節序列呈現:
(笨笨阿林原創文章,轉載請註明出處)
3、小結
1.
因爲UTF-8編碼方式以一個字節(8位)做爲碼元,屬於單字節碼元,在計算機處理、存儲和傳輸時不存在字節序問題(字節序問題只跟多字節碼元有關),所以避免了平臺依賴性,跨平臺兼容性好。
它相對於其餘編碼方式對英語更爲友好,一樣也對計算機語言(如C++、Java、C#、JavaScript、PHP、HTML等)更爲友好。它在處理ASCII等經常使用字符集時不多會比UTF-16低效。
2.
因此,UTF-8是較爲平衡、較爲理想的Unicode編碼方式。雖然Windows平臺因爲歷史的緣由API缺少對UTF-8的原生支持(Windows原生支持的是UTF-16,由於UTF-16早於UTF-8面世),致使UTF-8推出後的早期使用不廣,但目前是應用最爲普遍的三大UTF編碼方式之一。
所以,應該儘可能使用UTF-8(準確地說,應該儘可能使用UTF-8 without BOM,即不帶字節順序標記BOM的UTF-8)。
(笨笨阿林原創文章,轉載請註明出處)
(未完待續)
【預告:本《刨根究底字符編碼》系列的下一篇將重點剖析UTF-8到底是怎麼編碼的(即UTF-8的編碼算法介紹);而《刨根究底正則表達式》系列的下一篇爲正則表達式簡介(上),包括正則表達式的概念、功能、簡史、流派介紹,敬請關注!】