Unicode 字符集、編碼 相關的基本介紹


做者:shede333 html

主頁:http://my.oschina.net/shede333 && http://blog.sina.com.cn/u/1509658847
版權聲明:原創文章,版權聲明:自由轉載-非商用-非衍生-保持署名 | [Creative Commons BY-NC-ND 3.0][] python


Unicode

 
20世紀80年代末,
位於美國加州的組織容許任何願意支付會費的公司和我的加入,其成員包含了主要的電腦軟硬件廠商,例如奧多比系統蘋果公司惠普IBM微軟施樂等, 組成Unicode組織的商業機構 Unicode Consortium ,和國際合做的國際標準化組織  IEEE  由於電腦普及和信息國際化的前提下,分別各自成立了Unicode組織[2]和ISO-10646工做小組。他們不久便發現對方的存在,你們爲着相同的目的而工做。
1991年,Unicode Consortium與ISO/IEC JTC1/SC2贊成保持Unicode碼錶與ISO 10646標準保持兼容並密切協調各自標準進一步的擴展。雖然實際上二者的字集編碼相同,但實質上二者確實爲兩個不一樣的標準。

the  Unicode Consortium  開發了  The Unicode Standard  ("Unicode") , 目前Unicode的最新版本爲V8.0,Unicode的官網「 http://www.unicode.org/」 
ISO(或者叫 IEEE )開發了 ISO/IEC 10646 標準 通用字符集(Universal Character Set,UCS)是 ISO 10646(或稱ISO/IEC 10646)標準所定義的標準字符集
兩種標準字符集相互兼容,這兩個組織各自發布的標準有點複雜,暫時還沒徹底弄清楚

通用字符集 (Universal Character Set,UCS)  又稱Universal Multiple-Octet Coded Character Set,

我的理解 ,咱通俗的說Unicode, 通用字符集UCS,其實都是一回事,都指的是Unicode字符集。
Unicode編碼與 ISO 10646 的UCS( 通用字符集) 概念相對應。
下面我就統一用  Unicode



ISO/IEC 10646標準 與 Unicode標準 之間的關係,以下圖:





編碼


編碼方案,也叫實現方式,即把Unicode字符 以何種方式寫到硬盤上。
一個字符的Unicode編碼是肯定的。可是在實際傳輸過程當中,因爲不一樣 系統平臺 的設計不必定一致,以及出於節省空間的目的,對Unicode編碼的實現方式有所不一樣。Unicode的實現方式稱爲 Unicode轉換格式 (Unicode Transformation Format,簡稱爲UTF)
UTF是「 Unicode Transformation Format」的縮寫,能夠翻譯成Unicode字符集轉換格式,即怎樣將Unicode定義的數字轉換成程序數據。
而UTF8,UTF16,UTF32則是規定了Unicode字符按照指定的規則存儲到硬盤上了,也按照一樣的規則讀出來,屬於編碼。

Unicode有兩種編碼映射方法:  Unicode Transformation Format (UTF) 編碼 和    Universal Coded Character Set (UCS) 編碼 
編碼名字中的數字也表明必定的意思,UTF編碼的數字標明每一個碼點的bit數(我的理解:UTF-8最少8個位, UTF-16最少16位,UTF-32最少32位),UCS編碼的數字表明每一個碼值的字節數。

UCS-2用兩個字節編碼,UCS-4用4個字節編碼。

UTF-8 和UTF-16是目前最通用的編碼,web頁面,網絡傳輸主要用的是UTF-8,UCS相關的名稱如今說的不多了。
UCS-2是UTF-16的子集,如今要是說UCS-2的話,基本上指的是UTF-16;
UCS-4和UTF-32基本算是一個東西。 refer: Wiki-Unicode
後面講解UTF-16 和UTF-32是的時候,或詳細講解他們和UCS二、UCS4的區別


強調一下,Unicode只是一個抽象的標準而已,只作映射,不涉及到編碼的存儲策略,和密碼本相似,屬於字符集,指定了一個從字符到數字的映射;
Unicode的出現解決了在一篇文檔裏面出現多種語言的問題,在Unicode出現以前,每種字符集通常都是對應一種語言的。


Unicode能夠被不一樣的編碼方式實現,例如UTF8,UTF16, GB 18030





從這裏能夠很清楚地看到:
  1. 編碼是依賴於字符集的,就像代碼中的接口實現依賴於接口同樣;
  2. 一個字符集能夠有多個編碼實現,就像一個接口能夠有多個實現類同樣。



注意:
一個【字節】是8位二進制,可表示爲 0xFF,也可表示爲 1111 1111
【字符】,每一個Unicode碼位都是一個字符,「a」是一個字符,「王」也是一個字符,「😄」也是一個字符




UCS-4根據最高位爲0的最高字節分紅2 7=128 (2^7)個group。每一個group再根據次高字節 分爲256 (2^8)個平面(plane)。每一個平面根據第3個字節分爲256行 (row),每行有256個碼位(cell)。 group 0的平面0被稱做BMP( Basic Multilingual Plane 。group這個級別極少用

0x7F         0xFF      0xFF      0xFF
group       plane      row         cell 


若是UCS-4的前兩個字節爲全零,那麼將UCS-4的BMP去掉前面的兩個零字節就獲得了UCS-2。


目前的 Unicode字符分爲 17組0x0000 至 0x10 FFFF,共111 4112個。( int("0x10FFFF", 16) = 1114111 ), 有1,112,064個碼位(code point)可用來映射字符(這和UCS-4是兼容的) 每組稱爲平面(Plane),而每平面擁有65536(2^16)個碼位,
0號平面稱爲 BMP (後面有詳細的介紹BMP),承載了大部分經常使用字符, 其餘16個平面(1~16)稱爲 輔助平面 (Supplementary Planes)

Unicode最大字符爲 0x10 FFFF,那麼能夠理解爲21位的編碼方案( bin(0x10) == 0b10000,  21 = 5+4*4 )
雖然UCS-4的編碼最大能夠用31位,可是兩者已經達成協議,即便新加的字符也會保證分配到前17個平面(0~16)內,即0x0 ~   0x10 FFFF這個範圍,因此說兩者能夠說是一致的,後面我就仍是統一來Unicode這個名詞來講。

這可算是兩者的定義區別吧,但實際上二者是兼容的。後面咱們只以Unicode爲標準,編碼方面以UTF來說。

每一個平面有2 16=65536 個碼位。 Unicode計劃使用了17個平面,一共有17×65536=111 4112個碼位。
在Unicode 5.0.0版本中, 已定義的碼位只有238605個(並不表明有這麼多字符,只是說已經分配的,包括PUA等),分佈在平面0、平面一、平面二、平面1四、平面1五、平面16。

雖然計劃使用17個平面,但目前只有以下幾個平面才被用。


其中平面15和平面16上只是定義了 兩個各佔 65534個碼位的專用區(Private Use Area),分別是0xF0000-0xFFFF D和0x100000-0x10FFF D。所謂專用區,就是保留給你們放自定義字符的區域,能夠簡寫爲  PUA(後面有對PUA的詳細介紹)
平面0也有一個PUA專用區:0xE000-0xF8FF,有6400個碼位;
PUA區域不分配Unicode字符。

平面0的0xD800-0xDFFF,共2048個碼位,是一個被稱做代理區(Surrogate)的特殊區域,這個區域也不分配Unicode字符。 UTF-16就利用保留下來的0xD800-0xDFFF區段的碼位來對輔助平面的字符的碼位(BMP之外的字符 )進行編碼在介紹UTF-16編碼時會介紹

如前所述在 Unicode 5.0.0版本中, 238605-65534*2-6400-2048=99089(刪除平面1五、16,BMP平面上的PUA,BMP平面上的用於UTF-16的代理區)。餘下的99089個已定義碼位分佈在平面0、平面一、平面2和平面 14上,它們對應着Unicode定義的99089個字符,其中包括71226個漢字。
平面0、平面一、平面2和平面14上分別定義了52080、 341九、43253和337個字符。
平面2的43253個字符都是漢字。平面0上定義了27973個漢字。

在表示一個Unicode的字符時,一般會用 「U+xxxx」而後緊接着一組十六進制的數字( 4~6位)來表示這一個字符。在 基本多文種平面(英文爲  Basic Multilingual Plane,簡寫 BMP。它又簡稱爲「零號平面」, plane 0)裏的全部字符,要 用四位十六進制數(例如U+4AE0,共支持六萬多個字符)
在BMP平面之外的字符則須要使用 五位或六位十六進制數了。



Unicode 到目前爲止所定義的五個平面中(不包括1五、16的PUA平面),第0平面(BMP)最爲重要,包含了絕大部分經常使用字符

例如,「漢字」對應的數字是0x6c49和0x5b57,而編碼的程序數據是:





refer: Unicode 最新版 Character Code Charts (查找每一個字符的詳細解釋)




Basic Multilingual Plane(BMP)


BMP, 基本多文種平面又稱爲「零號平面」、plane 0, 包含了大部分的經常使用字符,然而,大部分的字符都分配給CJK了
BMP的字符的編碼爲 U+hhhh ,其中每一個 h 表明一個 十六進制 數字,與UCS-2編碼徹底相同

其中 (U+D800–U+DBFF) 和  (U+DC00–U+DFFF) 碼點被UTF-16佔用了,因此這部分不分配任何字符。


65,392 of the 65,536 code points in this plane have been allocated to a  Unicode block, leaving just 144 code points in unallocated ranges  (64 code points at 0860..089F, 64 code points at 1C80..1CBF, and 16 code points at 2FE0..2FEF).


A map of the Basic Multilingual Plane. Each numbered box represents 256 code points.


refer:  Wiki-Unicode block ( Unicode 的code point,即Unicode的分割區域所表明的意思)


Private Use Areas


在Unicode標準中, Private Use Area  ( PUA )範圍內的字符不會被分配出去,
目前,PUA有3個區域:
  1. BMP平面的(U+E000U+F8FF),
  2. planes 15 (U+F0000U+FFFFD)
  3. planes 16 (U+100000U+10FFFD)
three private use areas are defined: one in the  Basic Multilingual Plane (U+E000 U+F8FF ), and one each in, and nearly covering,  planes 15 and 16  (U+F0000 U+FFFFD ,U+100000 U+10FFFD ).
在這3個區域內的字符不能被分配給Unicode字符。Unicode是故意不分配這部分區域,目的是其餘的第三方機構可能會定義他們本身的字符,以此來避免與Unicode產生衝突




CJK


中日韓統一表意文字(CJK Unified Ideographs),目的是要把分別來自中文、日文、韓文、越文中,本質、意義相同、形狀同樣或稍異的表意文字(主要爲漢字,但也有仿漢字如日本國字、韓國獨有漢字、越南的 喃字)於ISO 10646及 Unicode標準內賦予相同編碼。 CJK 是中文(Chinese)、日文(Japanese)、韓文(Korean)三國文字的縮寫。顧名思義,它可以支持這三種文字。實際上,CJK 可以支持在 LaTeX 中使用包括中文、日文、韓文在內的多種亞洲雙字節文字。

注:中、日、韓文字裏面相同的字用的是同一個Unicode字符,這一點頗有爭議,由於,雖然是同一個字,可是在不一樣的語言裏面應該是不一樣的字形(字體),可是Unicode這樣的規定就致使了沒法給這個字符加上多種字體了。


refer:  CJK百度百科
refer:  字體編輯用中日韓漢字Unicode編碼表(注意,這只是漢字的一部分而已)


做者:shede333 ios


主頁:http://my.oschina.net/shede333 && http://blog.sina.com.cn/u/1509658847
版權聲明:原創文章,版權聲明:自由轉載-非商用-非衍生-保持署名 | [Creative Commons BY-NC-ND 3.0] web



UTF-8


UTF-8的特色是對不一樣範圍的字符使用不一樣長度的編碼。變長編碼
對於0x00-0x7F之間的字符,UTF-8編碼與 ASCII編碼徹底相同。
UTF-8編碼的 最大長度是6個字節。從下表能夠看出,6個字節的模板有31個x,便可以容納31位二進制數字。Unicode的最大碼位0x7FFF FFFF也只有31位。
在這些編碼中,性能最好,在絕大多少的網頁中使用的都是UTF-8
注:bin(0x7FFFFFFF) = ‘0b1111111111111111111111111111111’ 這個31位2進制
注:中文範圍 4E00-9FBF,也就是說每一箇中文字符的UTF-8編碼都是3個字節



注意:USC-4 的規定裏,最大能夠表示31位的字符,2^31 == 0x7FFF FFFF,UTF-8理論上能夠所有表示出來,
實際中,咱們使用Unicode規定的17個平面(0x0~0x10 FFFF),由此可看出,UTF-8最多用 4個字節便可表示Unicode目前已分配的字符

測試:
文檔存儲「哈」這1個字,保存成utf-8格式(不帶BOM),而後使用HexMiner來查看其真實內容:E59388
使用python查看 「哈」字的string存儲內容 '\xe5\x93\x88’ ,和上面是一致的
 

refer:  Wiki UTF-8



UTF-16


UTF-16是 變長編碼,UTF-16是UCS最第一版本的第一個修正案,是UCS-2的一個擴展,以此來表示BMP平面以外的碼點
如下摘自「Wiki UTF-16」的翻譯:
-------------
"Universal Character Set" (UCS)
在上世界80年代晚期,就開始了UCS計劃,最開始時打算用2個字節(2^16==65536)來表明一個字符,
最開始有兩個組織幹這個事情,   IEEE  and the  Unicode Consortium Unicode Consortium組織表明的是計算機設備製造商,兩者互相同步各自的字符分配策略,以便可以互相兼容;
早期, 這種的兩字節編碼被稱爲「Unicode」,可是如今被稱做「UCS-2」;
在指定Unicode的中早期,就發現65536字符(即兩字節編碼)是不夠用的,IEEE就引進了UCS-4標準(即每一個字符須要4個字節來表示),可是這個決定卻被 Unicode Consortium組織反對,反對的緣由有兩個:
  1. 一個字符用4個字節表示會浪費硬盤和內存空間;
  2. 許多計算機制造商已經在UCS-2技術上投入了大量資金;
在發佈Unicode 2.0版本的時候,UTF-16就被IEEE開發出來解決這兩個組織的僵局。
---------

UTF-16編碼以16位無符號整數爲單位。咱們把Unicode編碼記做U。編碼規則以下:
如今定義一個新單位,定義2個字節(即16位)爲一個Word,那麼以上U<0x10000編碼的的字符就是是一個Word;
若是U<0x10000,U的UTF-16編碼就是U對應的16位無符號整數(爲書寫簡便,下文將16位無符號整數記做WORD)。
若是U≥0x10000,咱們先計算U’=U - 0x10000,而後將U'寫成二進制(5個字節)形式:yyyy yyyy yyxx xxxx xxxx,
那麼U的UTF-16編碼(二進制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。

按照上述規則,Unicode編碼0x10000-0x10FFFF的UTF-16編碼有兩個WORD,第一個WORD的高6位是110110,第二個WORD的高6位是110111。可見,
第一個高位WORD的取值範圍(二進制)是 1101 1000 0000 0000到 1101 1011 1111 1111,即 0xD800-0xDBFF
第二個低位WORD的取值範圍(二進制)是 1101 1100 0000 0000到 1101 1111 1111 1111,即 0xDC00-0xDFFF
爲了將一個WORD的UTF-16編碼與兩個WORD的UTF-16編碼區分開來,Unicode編碼的設計者將 0xD800-0xDFFF保留下來,並稱爲代理區(Surrogate):


由上所知:

當在一個 UTF-16 編碼的字符串裏發如今 0xD800-0xDFFF這個範圍內的序列時,就能馬上知道這是某個代理對的一部分
即在UTF-16中,對於U<0x10000的字符,UTF-16編碼和Unicode編碼都用兩個字節表示,並且編碼內容也相同;
對於U≥0x10000這部分字符,須要使用使用兩個Word來表示(即4個字節),並且每一個Word的最高位被定死了,第一個Word的最高6位爲110110, 第2個Word的最高6位爲110111,
能夠想象,之因此把兩個Word的最高位定死,就是爲了把這種兩個Word表示一個字符的 和 一個Word表示一個字符的區分開,那麼,若是第一個Word的110110******能夠表示一個正常的Unicode字符的話,那麼咱們就分不清110110******究竟是表示一個字符呢,仍是表示兩個Word的高位。
注:在提出UTF-16以前(即UCS-2)上 0xD800-0xDFFF是有分配Unicode字符的,在推出UTF-16以後才把這部分的字符分配去掉的。

Example 1:


用十進制作一個例子,一開始要求要表示50個字符:
那麼咱們規定用兩位十進制來表示一個字符,這樣咱們就能表示100個字符了(0~99),而咱們只用了前50個字符,後50個字符都還沒分配;
而後來有需求變動了,須要表示的字符增長到了 120 個了,同時要求兼容以前的50個字符標準:
那麼咱們規定,對於  0~79的字符 只能使用2位十進制, 十位只能使用0~7, 個位隨意,這樣就能用兩位十進制表示80個字符;
對於大於80的字符,咱們使用2個十進制數(即4位)來表示一個字符,這兩個十進制分爲高位、低位,高位數的十位只能爲8, 低位數的十位用9

對於小於80的數字 ,例如要表示數字12,那麼就用 12 來表示
對於大於等於80的數字須要使用兩個十進制數字表示,例如要表示數字80,那麼就用 80 80,其他的表示方法以下

原始字符       編碼後的表示方式
80                       80 90
81                       80 91
82                       80 92
83                       80 93
……..
90                       81 90
91                       81 91
92                       81 92
……..
100                     82 90
101                     82 91
102                     82 92

這樣,當出現如下編碼,咱們就知道表示什麼意思了(忽略空格)
編碼後(存在硬盤上的內容)  34  82 95 56  80 94  
要表達的原始字符               34  105 56  84

Example 2:




我的理解:
下面只針對於UTF16大於0x10000部分,
因爲目前Unicode的範圍是0x0 ~ 0x10FFFF,BMP平面以外的字符範圍是 0x1 0000 ~ 0x10 FFFF;
Unicode表示 0x10 FFFF個字符,那麼須要21個bit位(bin(0x10) = 0b10000 即5位二進制,21 = 5+ 4*4),UTF-16須要把這些字符都表示出來
可是UTF16須要減去0x1 0000,那麼就至關於 UTF16 用 0x0 ~ 0xF FFFF 去表示Unicode的 0x1 0000 ~ 0x10 FFFF,(0x10 FFFF - 0xF FFFF  == 0x1 0000 )
這麼看的話UTF16 只須要 表示0xF FFFF個字符便可,即20個bit位,那麼咱們來算一下,UTF-16的這種2個Word能不能表示出來這20個bit位。
UTF16一個Word是兩個字節(16個bit位),而後減去6個高位bit,那麼一個Word的有效bit位是10,兩個Word的有效bit位正好也是20,
這樣看的話,UTF-16這種方法,用兩個Word正好能夠表示Unicode 大於0x1 0000的部分(BMP平面之外的部分)。

UTF-16,大部分字符使用 兩個字節就能夠表示,對於unicode的U≥0x10000,就要使用 四個字節了(即兩個Word)。

建立一個文本,裏面內容爲「你好」,保存爲 UTF-16 BE  ,大端
那麼文件的存儲內容爲

大端的BOM爲 FEFF,你(\u4f60) 好(\u597d),這就明白上面的存儲的內容了吧

refer:  Wiki UTF-16



UTF-32


最初,   ISO 10646  定義了31位編碼標準,叫作UCS-4,UCS裏的每個字符都是用32位碼點表示(0 ~ 0x7FFF FFFF).
UCS-4是一個更大的還沒有填充徹底的31位字符集,加上恆爲0的首位,共需佔據32位,即4字節。理論上最多能表示2 31 個字符,徹底能夠涵蓋一切語言所用的符號。
因爲目前僅僅有17個平面在使用(0~0x10),全部的碼點都在  0 and 0x10FFFF範圍內,這就是UTF-32的編碼範圍,因此說,UTF-32是UCS-4的子集;
根據   JTC1/SC2/WG2規定,將來分配的新字符都被限制在 BMP平面(0 plane) 和前14 個平面內(1五、16平面只能用於PUA),這樣UTF-32就能表示全部的Unicode字符,因此UCS-4和UTF32是一致的。


UTF-32編碼以32位無符號整數爲單位。Unicode的UTF-32編碼就是其對應的32位無符號整數。
定長編碼,4字節表示一個字符,並且UTF-32編碼的值 和 Unicode標準的值一一對應,相對於其餘變長編碼,UTF-32的優勢以下:
從編碼值找到要表示的Unicode值是很快的,花費的時間是固定的,應爲兩者的值是同樣的,而變長編碼須要花費一些時間去作轉換;
UTF-32最大的缺點:太浪費空間了,由於在文本里面,大部分都是BMP平面的字符


字節序:
字節序有兩種,分別是「大端」(Big Endian, BE)和「小端」(Little Endian, LE)。
在UTF-16中,字節序是以 2個字節爲單位的,在每一個單位內分  字節序(見下面高亮部分);
在UTF-32中,字節序是以 4個字節爲單位的,在每一個單位內分  字節序

根據字節序的不一樣,UTF-16可被實現爲UTF-16LE或UTF-16BE,UTF-32可被實現爲UTF-32LE或UTF-32BE,以下圖:
Unicode編碼 UTF-16LE  UTF-16BE  UTF32-LE  UTF32-BE
0x6C49 49 6C 6C 49 49 6C 00 00 00 00 6C 49
0x020C30 43 D8 30 DC D8 43 DC 30 30 0C 02 00 00 02 0C 30



refer:  Wiki UTF-32



BOM(Byte Order Mark)


字節序
Unicode標準建議用 BOM(Byte Order Mark)來區分字節序,即在傳輸字節流前,先傳輸被做爲BOM的字符「零寬無中斷空格」。
若是 最低有效位 最高有效位 的前面,則稱 小端序 ;反之則稱 大端序
好比數字 12,最低有效位是個位數 1,通常來講,內存地址都是從左到右遞增,那麼
小端的存儲就是  2 1
大端的的存儲是  1 2
以上同理能夠應用到16進製表示法上。

在內存裏存儲字符串時,大多數實現方式天然都採用本身運行平臺的 CPU 的字節序(endianness);而在硬盤裏存儲或者經過網絡傳輸字符串時,UTF-16 容許在字符串的開頭插入一個「字節序標記」(Byte Order Mask,BOM)
UTF-16 須要指明字節順序,這也是爲何 UTF-16 在文件格式和網絡傳輸方面不受歡迎的一個緣由,不過微軟和蘋果都在本身的操做系統內部使用它。


下表是各類UTF編碼的BOM:
UTF編碼 Byte Order Mark (BOM)
UTF-8 without BOM
UTF-8 with BOM EF BB BF
UTF-16LE FF FE
UTF-16BE FE FF
UTF-32LE FF FE 00 00
UTF-32BE 00 00 FE FF


由上所知:
UTF-32編碼使用 4個字節
通常來講,只有UTF-16 和UTF-32須要使用字節序,UTF-8不多須要,由於UTF-8就一種字節序,
使用python裏的文件讀取操做讀取正常的UTF-8文件(沒有BOM), open(「文件路徑」, 「rb」).read() 便可得到內容
若是讀取帶有BOM的UTF-8文件,open(「文件路徑」, 「rb」).read() 獲取的字符中,前幾位會亂碼,即BOM,若是這是一個json文件,那麼一些json庫就沒法正確讀取這些文件
要讀取帶有BOM的UTF-8文件,獲取的內容又不帶BOM,那麼就要用  open(「文件路徑」, 「rb」).read().decode(「utf-8-sig")






Unicode In iOS


@"\U0001f604」 等同於字符 😄 ,當此字符串的長度 是  2
@"\u54c8」 等同於 @「哈」 , 字符長度爲1
就是說把BMP平面之外的字符長度當成2了
在蘋果官方文檔中  The Unicode Basis of CFString Objects中,
CFString 表明了一個 Unicode 字符組成的數組和一個字符總數的計數。……Unicode 標準定義了一個通用、統一的編碼方案,其中每一個字符 16 位。
這應該就是計算BMP平面之外字符的長度錯誤的緣由了吧,每一個字符16位是UCS-2那個時代的事情了

若是你很在乎長度的話,要解決計算長度計算錯誤,能夠轉爲UTF32後再去計算啊,看樣子UTF32也不是一無可取啊
NSString *s = @"\U0001F30D"; // earth globe emoji  
NSLog(@"The length of %@ is %lu", s, [s length]);  // 長度爲 2
NSUInteger realLength = [s lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4; // realLength 爲1

另外對 組合字符序列,變體序列的長度計算也是有問題的,這個就不能用UTF-32解決
例如 加劇音符號的e是「é」,é用Unicode表示的話須要兩個字符組合起來,即小寫e加劇音符號
NSString *s = @"e\u0301";
NSLog(@"%@,%d", s, s.length);  // 輸出  é,2
但實際上é對咱們來講算一個字符的,長度應該爲2,這種問題的處理方法也是有的,可是這裏就不展開說明了,代碼以下:
NSString *n = [s precomposedStringWithCanonicalMapping]; 
NSLog(@"The length of %@ is %lu", n, [n length]); 
// => The length of é is 1

é既可使用上面說的組合方法表示,同時é其實也是單個Unicode字符"\u00e9"
NSString *s1 = @"\u00e9";
NSString *s2 = @"e\u0301";
NSLog(@"%@, %@, %d", s1, s2, [s1 isEqualToString:s2]);  //輸出結果: é, é, 0
s1,s2明明是同樣的字符,可是isEqualToString方法去返回NO,這是由於NSString的「isEqualToString」方法只是一個個字節的比較,因此會得出不相等的結論
解決辦法以下:
// Normalizing to form C
NSString *sNorm = [s precomposedStringWithCanonicalMapping];
NSString *tNorm = [t precomposedStringWithCanonicalMapping];
BOOL isEqualNorm = [sNorm isEqualToString:tNorm];
NSLog(@"%@ is %@ to %@", sNorm, isEqualNorm ? @"==" : @"!=", tNorm);   // 輸出 é == é




Apple在PUA區域裏面定義了一下字符( 文檔點這裏),雖然大多數已經再也不使用了,可是蘋果的 logo 是個著名的例外:,它的碼點是 U+F8FF。(你可能看到的是另外一個不一樣的字符,這取決於你閱讀本文的平臺,理論上只有在Apple平臺上才能看到這個字符)。

NSString 表明的是用 UTF-16 編碼的文本,長度、索引和範圍都基於 UTF-16 的碼元。
我的理解:NSString之因此在BMP之外的字符長度計算錯誤,是爲了保證快速的(時間複雜度 O(1) 級別)與 UTF-16 碼元轉換。

NSString 裏面想要插入Unicode字符,可用以下方式:
BMP平面內(Unicode的碼值 <  0x10000 ):@「\u266A」(♪)的方式輸入, 最頭上的u要小寫,後面的其餘字符不區分大小寫
也可使用這種方式 @「\U0001F340」(🍀 )的方式輸入( 最頭上的U要大寫),這種方式主要爲BMP平面之外的部分用,固然,BMP平面內的也能夠用
另外,C99 不容許標準 C 字符集裏的字符用通用字符名(universal character name)來指定,所以不能這樣寫   NSString *s = @"\u0041"
我測試了一下,ASCII碼的都不能用,後128位部分不能用。

這部分還沒看完,待續~~~





ANSI編碼

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

不一樣的國家和地區制定了不一樣的標準,由此產生了 GB23十二、GBK、Big五、Shift_JIS 等各自的編碼標準。這些使用 1 至 4 個字節來表明一個字符的各類漢字延伸編碼方式,稱爲 ANSI 編碼。在簡體中文Windows操做系統中,ANSI 編碼表明 GBK 編碼;在日文Windows操做系統中,ANSI 編碼表明 Shift_JIS 編碼。 不一樣 ANSI 編碼之間互不兼容,當信息在國際間交流時,沒法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。 固然對於ANSI編碼而言,0x00~0x7F之間的字符,依舊是1個字節表明1個字符。這一點是ANSI編碼與Unicode編碼之間最大也最明顯的區別。






ASCII


"Ascii"編碼(American Standard Code for Information Interchange,美國信息互換標準代碼)。
在windows中, 對於英文系統即 ASCII 編碼,中文系統則爲 GB2312 Big5 編碼




Unicode 額外介紹


再說一下,這些Unicode字符不是單獨存在的,他們能夠互相組合的,
例如,有重音符號的字母 é 能夠直接表示成 U+00E9(「有尖音符號的小寫拉丁字母 e」),或者也能夠表示成由 U+0065(「小寫拉丁字母 e」)再加 U+0301(「尖音符號」)組成的分解形式。這兩個形式都是組合字符序列的變體;
再就是,許多看上去同樣的字符都在不一樣的碼點編碼了屢次,以此來表明不一樣的含義。
對以上內容感興趣的話,能夠搜索  相容等價(compatibility equivalence) 、  標準等價(canonically equivalent),組合字符序列,變體序列




注意:

1.百度百科上的介紹有些錯誤,更新也不及時, 強烈建議到Wiki上看資料
2.用Python查看UTF-8編碼後的內容是沒問題的,估計是由於UTF-8的每一個字節都是1開頭的,越過了ASCII碼,
而用查看UTF-16編碼後的內容,有不少字符被解釋成ASCII碼後,就看不到原始內容了
3.使用 Python查看Unicode字符的一些方法,
想要查看某漢字的碼點,好比查看 「好」字的碼點:  " 好".decode("utf-8")  //注意:後面的「utf-8」是平臺的默認編碼,若是你的平臺默認編碼不是utf-8的話,改你你當前平臺的默認編碼便可。
想要查看某碼點表明的字符,例如查看「U+597d」這個碼點表明的字符: print u"\u597d" 或者  print u"\U0000597d」;
4位16進制數字( \u597d)的表示方法:小寫的u ,加「\」 ,加 4位Unicode的16進制的碼點;
8位16進制數字( \U0000597d)的表示方法:大寫的U ,加「\」 ,加 8位Unicode的16進制的碼點;
對於小於0x1 0000的字符(BMP平面內的),4和和8位的表示方法均可以;
對於大於等於0x1 0000之外的字符,必須使用8位16進制數字表示方法。
4.上面引用的一些圖片,想要查看出處,點擊圖片便可。

工具:
  1. Hex Friend
  2. File Info Professional
參考:

注意,下面的中文文檔並非英文版的翻譯,兩者不太相關,但英文版的介紹更豐富,建議看看英文版的










字體編輯用中日韓漢字Unicode編碼表(注意,這只是漢字的一部分而已)

另外:


對字符編碼感興趣的話,推薦看下如下的文章:

相關文章
相關標籤/搜索