Unicode 與 Unicode Transformation Format(UTF-8 / UTF-16 / UTF-32)

  • ASCII(American Standard Code for Information Interchange):早期它使用7 bits來表示一個字符,總共表示27=128 個字符;後來擴展到8 bits,即用一個字節來表示一個字符,總共表示28=256 個字符,這種ASCII擴展字符集如IBM字符集和ISO Latin-1,首位爲1(128~255)的編碼區域表示擴展字符
  • Unicode:由於ASCII字符集總數有限且只適用於歐洲語言國家,不同語言體系的國家要統一使用同一種字符集,就需要一種更大的字符集。Unicode早期採用2個字節編碼,總共可表示216=65536 個字符,它通過增加一個高字節對ISO Latin-1字符集進行擴展,當這些高字節位爲0時,低字節就是ISO Latin-1字符;然而,可以用ASCII表示的字符使用Unicode並不高效,因爲Unicode比ASCII佔用大一倍的空間,對ASCII來說高字節的0對他毫無用處。爲了解決這個問題,就出現了一些中間格式的字符集,他們被稱爲通用轉換格式,即UTF(Unicode Transformation Format),如UTF-8、UTF-16、UTF-32。Universal Character Set(UCS)是由ISO制定的ISO 10646(或稱ISO/IEC 10646)標準所定義的標準字符集,UCS-2用兩個字節編碼,UCS-4用4個字節編碼。從Unicode 2.0開始,Unicode採用了與ISO 10646-1相同的字庫和字碼,以保持兩者兼容。Unicode計劃使用17個平面(Plane,包含216=65536 個碼位。Plane 0被稱爲Basic Multilingual Plane),一共有17×65536=1114112個碼位(0~1114111)。ISO承諾ISO 10646將不會替超出U+10FFFF(1114111)的UCS-4編碼賦值,以使得兩者保持一致
  • BOM(Byte Order Mark,字節順序標記):特殊字符U+FEFF叫做 “Zero Width No-Break Space” ,中文譯作“零寬無間斷間隔”的字符,實際不會出現在正常字節流中。但在傳輸字節流前,先傳輸字符 “Zero Width No-Break Space”,如果收到FFFE,就表明這個字節流是 Little- Endian (小端序、小字節序、低字節序、小尾序,即低位字節排放在內存的低地址端,高位字節排放在內存的高地址端)的;如果收到 FEFF,就表明這個字節流是 Big-Endian (大端序,字節順序與 Little- Endian 剛好相反)的。因此字符 “Zero Width No-Break Space” 又被稱作 BOM,它將出現在文本文件頭部,表明文件的編碼方式。UTF-8 雖是字節順序無關的,但仍然可以用 BOM (EF BB BF)來表明其編碼方式。下圖展示了編碼方式與BOM的對應關係:
    編碼方式與BOM的對應關係
    PHP並不會忽略UTF-8文件的BOM,所以在讀取、包含或者引用這些文件時,會把BOM作爲該文件開頭正文的一部分。因此,PHP文件採用UTF-8編碼時可保存無BOM格式。
    如果U+FEFF出現在數據流中,該怎麼辦呢?下面這段來自Wikipedia,關於Word Joiner(WJ, U+2060):
    The word joiner replaces the zero-width no-break space (ZWNBSP), a deprecated use of the Unicode character at code point U+FEFF. Character U+FEFF is intended for use as a Byte Order Mark at the start of a file. However, if encountered elsewhere it should, according to Unicode, be treated as a "zero-width non-breaking space." The deliberateee use of U+FEFF for this purpose is deprecated as of Unicode 3.2, with the word joiner strongly preferred.

  • UTF-8(萬國碼):它是可變長編碼,即用1~4個字節來編碼Unicode字符集。其與Unicode的轉換關係如下:
    UTF-8與Unicode的轉換關係
    另外,以下部分非Unicode編碼範圍,屬於UCS-4 編碼早期的規範:
    UTF-8與Unicode的轉換關係
    UTF-8用1個字節(U+0000~U+007F)來編碼所有ASCII字符,並且與ASCII字符表示是一樣的,故其與ASCII兼容,而那些ISO Latin-1擴展ASCII字符集的字符(128~255)是Unicode的子集,但不是UTF-8的子集;其他的字符UTF-8編碼將需要2~4個字節,首字節連續的1的個數表示字符編碼所需的字節數。“編”的Unicode編碼是U+7F16,因此UTF-8需要3個字節來表示,形如1110xxxx 10xxxxxx 10xxxxxx這種格式。
    由於UTF-8採用的是變長字符編碼,與UTF-16和UTF-32相比,無論是計算字符數,還是執行索引操作效率都不高,因此UTF-8適合在傳輸數據中使用,可在數據接收完畢後將其轉換爲UTF-16或UTF-32進行處理,最後再轉換回UTF-8(但這轉換本身也會有性能損耗);但UTF-8空間足夠大,無字節序問題,且容錯性高,局部的字節錯誤(丟失、增加、改變)不會導致連鎖性的錯誤,因爲 UTF-8 的字符邊界很容易檢測出來

  • UTF-16:以2個字節16bits爲編碼基本單位。假設U代表字符的Unicode編碼,如果U < 0x10000且U∉[0xD800,0xDFFF],U的UTF-16編碼就是U對應的16位無符號整數(0x0000~0xFFFF,除去0xD800-0xDFFF作爲BMP的代理區部分);如果U ≥ 0x10000,則使U’ = U - 0x10000(最大爲0x10FFFF - 0x10000 = 0xFFFFF),然後將U’寫成二進制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16編碼二進制表示就是:110110yyyyyyyyyy(0xD800~0xDBFF) 110111xxxxxxxxxx(0xDC00~0xDFFF)。由此可見,Unicode字符的UTF-16表示要麼是2個字節長度,要麼是4個字節長度,爲將二者區分開來、防止衝突,設計者將0xD800-0xDFFF保留下來,稱代理區(Surrogate):
    代理區(Surrogate)
    High Surrogates就是指這個範圍的碼位是Unicode字符4字節UTF-16編碼的頭兩個字節;Low Surrogates就是指這個範圍的碼位是Unicode字符4字節UTF-16編碼的後兩個字節;High Private Use Surrogates是指這個範圍的碼位是Unicode字符4字節UTF-16編碼的頭兩個字節,但該Unicode字符屬於平面15和平面16這兩個專用區

  • UTF-32:用4個字節32bits來編碼一個Unicode字符,Unicode的UTF-32編碼就是其對應的32位無符號整數

  • 更多信息參考鏈接http://www.unicode.org/faq/utf_bom.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章