- 上一篇:《新編高中文言文助讀》
- 下一篇:2006年最佳政治漫畫
分類:
字符編碼筆記:ASCII,Unicode 和 UTF-8
作者: 阮一峯
日期: 2007年10月28日
今天中午,我突然想搞清楚 Unicode 和 UTF-8 之間的關係,就開始查資料。
這個問題比我想象的複雜,午飯後一直看到晚上9點,纔算初步搞清楚。
下面就是我的筆記,主要用來整理自己的思路。我儘量寫得通俗易懂,希望能對其他朋友有用。畢竟,字符編碼是計算機技術的基石,想要熟練使用計算機,就必須懂得一點字符編碼的知識。
一、ASCII 碼
我們知道,計算機內部,所有信息最終都是一個二進制值。每一個二進制位(bit)有0
和1
兩種狀態,因此八個二進制位就可以組合出256種狀態,這被稱爲一個字節(byte)。也就是說,一個字節一共可以用來表示256種不同的狀態,每一個狀態對應一個符號,就是256個符號,從00000000
到11111111
。
上個世紀60年代,美國製定了一套字符編碼,對英語字符與二進制位之間的關係,做了統一規定。這被稱爲 ASCII 碼,一直沿用至今。
ASCII 碼一共規定了128個字符的編碼,比如空格SPACE
是32(二進制00100000
),大寫的字母A
是65(二進制01000001
)。這128個符號(包括32個不能打印出來的控制符號),只佔用了一個字節的後面7位,最前面的一位統一規定爲0
。
二、非 ASCII 編碼
英語用128個符號編碼就夠了,但是用來表示其他語言,128個符號是不夠的。比如,在法語中,字母上方有注音符號,它就無法用 ASCII 碼錶示。於是,一些歐洲國家就決定,利用字節中閒置的最高位編入新的符號。比如,法語中的é
的編碼爲130(二進制10000010
)。這樣一來,這些歐洲國家使用的編碼體系,可以表示最多256個符號。
但是,這裏又出現了新的問題。不同的國家有不同的字母,因此,哪怕它們都使用256個符號的編碼方式,代表的字母卻不一樣。比如,130在法語編碼中代表了é
,在希伯來語編碼中卻代表了字母Gimel
(ג
),在俄語編碼中又會代表另一個符號。但是不管怎樣,所有這些編碼方式中,0--127表示的符號是一樣的,不一樣的只是128--255的這一段。
至於亞洲國家的文字,使用的符號就更多了,漢字就多達10萬左右。一個字節只能表示256種符號,肯定是不夠的,就必須使用多個字節表達一個符號。比如,簡體中文常見的編碼方式是 GB2312,使用兩個字節表示一個漢字,所以理論上最多可以表示 256 x 256 = 65536 個符號。
中文編碼的問題需要專文討論,這篇筆記不涉及。這裏只指出,雖然都是用多個字節表示一個符號,但是GB類的漢字編碼與後文的 Unicode 和 UTF-8 是毫無關係的。
三. Unicode
正如上一節所說,世界上存在着多種編碼方式,同一個二進制數字可以被解釋成不同的符號。因此,要想打開一個文本文件,就必須知道它的編碼方式,否則用錯誤的編碼方式解讀,就會出現亂碼。爲什麼電子郵件常常出現亂碼?就是因爲發信人和收信人使用的編碼方式不一樣。
可以想象,如果有一種編碼,將世界上所有的符號都納入其中。每一個符號都給予一個獨一無二的編碼,那麼亂碼問題就會消失。這就是 Unicode,就像它的名字都表示的,這是一種所有符號的編碼。
Unicode 當然是一個很大的集合,現在的規模可以容納100多萬個符號。每個符號的編碼都不一樣,比如,U+0639
表示阿拉伯字母Ain
,U+0041
表示英語的大寫字母A
,U+4E25
表示漢字嚴
。具體的符號對應表,可以查詢unicode.org,或者專門的漢字對應表。
四、Unicode 的問題
需要注意的是,Unicode 只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。
比如,漢字嚴
的 Unicode 是十六進制數4E25
,轉換成二進制數足足有15位(100111000100101
),也就是說,這個符號的表示至少需要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚至更多。
這裏就有兩個嚴重的問題,第一個問題是,如何才能區別 Unicode 和 ASCII ?計算機怎麼知道三個字節表示一個符號,而不是分別表示三個符號呢?第二個問題是,我們已經知道,英文字母只用一個字節表示就夠了,如果 Unicode 統一規定,每個符號用三個或四個字節表示,那麼每個英文字母前都必然有二到三個字節是0
,這對於存儲來說是極大的浪費,文本文件的大小會因此大出二三倍,這是無法接受的。
它們造成的結果是:1)出現了 Unicode 的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示 Unicode。2)Unicode 在很長一段時間內無法推廣,直到互聯網的出現。
五、UTF-8
互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8 就是在互聯網上使用最廣的一種 Unicode 的實現方式。其他實現方式還包括 UTF-16(字符用兩個字節或四個字節表示)和 UTF-32(字符用四個字節表示),不過在互聯網上基本不用。重複一遍,這裏的關係是,UTF-8 是 Unicode 的實現方式之一。
UTF-8 最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。
UTF-8 的編碼規則很簡單,只有二條:
1)對於單字節的符號,字節的第一位設爲0
,後面7位爲這個符號的 Unicode 碼。因此對於英語字母,UTF-8 編碼和 ASCII 碼是相同的。
2)對於n
字節的符號(n > 1
),第一個字節的前n
位都設爲1
,第n + 1
位設爲0
,後面字節的前兩位一律設爲10
。剩下的沒有提及的二進制位,全部爲這個符號的 Unicode 碼。
下表總結了編碼規則,字母x
表示可用編碼的位。
Unicode符號範圍 | UTF-8編碼方式 (十六進制) | (二進制) ----------------------+--------------------------------------------- 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
跟據上表,解讀 UTF-8 編碼非常簡單。如果一個字節的第一位是0
,則這個字節單獨就是一個字符;如果第一位是1
,則連續有多少個1
,就表示當前字符佔用多少個字節。
下面,還是以漢字嚴
爲例,演示如何實現 UTF-8 編碼。
嚴
的 Unicode 是4E25
(100111000100101
),根據上表,可以發現4E25
處在第三行的範圍內(0000 0800 - 0000 FFFF
),因此嚴
的 UTF-8 編碼需要三個字節,即格式是1110xxxx 10xxxxxx 10xxxxxx
。然後,從嚴
的最後一個二進制位開始,依次從後向前填入格式中的x
,多出的位補0
。這樣就得到了,嚴
的 UTF-8 編碼是11100100 10111000 10100101
,轉換成十六進制就是E4B8A5
。
六、Unicode 與 UTF-8 之間的轉換
通過上一節的例子,可以看到嚴
的 Unicode碼 是4E25
,UTF-8 編碼是E4B8A5
,兩者是不一樣的。它們之間的轉換可以通過程序實現。
Windows平臺,有一個最簡單的轉化方法,就是使用內置的記事本小程序notepad.exe
。打開文件後,點擊文件
菜單中的另存爲
命令,會跳出一個對話框,在最底部有一個編碼
的下拉條。
裏面有四個選項:ANSI
,Unicode
,Unicode big endian
和UTF-8
。
1)ANSI
是默認的編碼方式。對於英文文件是ASCII
編碼,對於簡體中文文件是GB2312
編碼(只針對 Windows 簡體中文版,如果是繁體中文版會採用 Big5 碼)。
2)Unicode
編碼這裏指的是notepad.exe
使用的 UCS-2 編碼方式,即直接用兩個字節存入字符的 Unicode 碼,這個選項用的 little endian 格式。
3)Unicode big endian
編碼與上一個選項相對應。我在下一節會解釋 little endian 和 big endian 的涵義。
4)UTF-8
編碼,也就是上一節談到的編碼方法。
選擇完"編碼方式"後,點擊"保存"按鈕,文件的編碼方式就立刻轉換好了。
七、Little endian 和 Big endian
上一節已經提到,UCS-2 格式可以存儲 Unicode 碼(碼點不超過0xFFFF
)。以漢字嚴
爲例,Unicode 碼是4E25
,需要用兩個字節存儲,一個字節是4E
,另一個字節是25
。存儲的時候,4E
在前,25
在後,這就是 Big endian 方式;25
在前,4E
在後,這是 Little endian 方式。
這兩個古怪的名稱來自英國作家斯威夫特的《格列佛遊記》。在該書中,小人國裏爆發了內戰,戰爭起因是人們爭論,吃雞蛋時究竟是從大頭(Big-endian)敲開還是從小頭(Little-endian)敲開。爲了這件事情,前後爆發了六次戰爭,一個皇帝送了命,另一個皇帝丟了王位。
第一個字節在前,就是"大頭方式"(Big endian),第二個字節在前就是"小頭方式"(Little endian)。
那麼很自然的,就會出現一個問題:計算機怎麼知道某一個文件到底採用哪一種方式編碼?
Unicode 規範定義,每一個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫做"零寬度非換行空格"(zero width no-break space),用FEFF
表示。這正好是兩個字節,而且FF
比FE
大1
。
如果一個文本文件的頭兩個字節是FE FF
,就表示該文件採用大頭方式;如果頭兩個字節是FF FE
,就表示該文件採用小頭方式。
八、實例
下面,舉一個實例。
打開"記事本"程序notepad.exe
,新建一個文本文件,內容就是一個嚴
字,依次採用ANSI
,Unicode
,Unicode big endian
和UTF-8
編碼方式保存。
然後,用文本編輯軟件UltraEdit 中的"十六進制功能",觀察該文件的內部編碼方式。
1)ANSI:文件的編碼就是兩個字節D1 CF
,這正是嚴
的 GB2312 編碼,這也暗示 GB2312 是採用大頭方式存儲的。
2)Unicode:編碼是四個字節FF FE 25 4E
,其中FF FE
表明是小頭方式存儲,真正的編碼是4E25
。
3)Unicode big endian:編碼是四個字節FE FF 4E 25
,其中FE FF
表明是大頭方式存儲。
4)UTF-8:編碼是六個字節EF BB BF E4 B8 A5
,前三個字節EF BB BF
表示這是UTF-8編碼,後三個E4B8A5
就是嚴
的具體編碼,它的存儲順序與編碼順序是一致的。
九、延伸閱讀
- The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets(關於字符集的最基本知識)
- 談談Unicode編碼
- RFC3629:UTF-8, a transformation format of ISO 10646(如果實現UTF-8的規定)
(完)
文檔信息
- 版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)
- 發表日期: 2007年10月28日
- 更多內容: 檔案 » 理解計算機
- 文集:《前方的路》,《未來世界的倖存者》
- 社交媒體: twitter, weibo
相關文章
- 2018.07.16: CAP 定理的含義
分佈式系統(distributed system)正變得越來越重要,大型網站幾乎都是分佈式的。
- 2018.05.09: 根域名的知識
域名是互聯網的基礎設施,只要上網就會用到。
- 2018.01.21: 彙編語言入門教程
學習編程其實就是學高級語言,即那些爲人類設計的計算機語言。
- 2018.01.11: 加密貨幣的本質
現在,各種加密貨幣(cryptocurrency)不計其數。
廣告(購買廣告位)
留言(218條)
Stark 說:
很有意思的內容
講解得通俗易懂,非常感謝您用較長的時間學習,並用精簡的語言概括
flyisland 說:
本人是計算機從業人員,對文中提到的知識也都基本瞭解,但是像阮兄這樣,花了半天時間就弄清楚來龍去脈,同時講述的如此清楚,實在佩服。
本帖有pmp嫌疑,但實在是不能不p啊 :)。我想,動手寫過技術文章的人都會同意我的。
只如初見 說:
是啊,我這個超級菜鳥都看明白了,阮兄對技術的理解和說明能力叫人佩服,謝謝分享。
姬着 說:
文章裏說:UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。
那USC-2編碼方式如何實現超過兩個字節的符號的存儲?謝謝
大徐 說:
對了解字符編碼很有幫助,謝謝!
Ruan YiFeng 說:
引用只如初見的發言:是啊,我這個超級菜鳥都看明白了,阮兄對技術的理解和說明能力叫人佩服,謝謝分享。
“延伸閱讀”中第一個鏈接,纔是真正的通俗易懂,我只是向他學習而已。
Ruan YiFeng 說:
引用姬着的發言:文章裏說:UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。 那USC-2編碼方式如何實現超過兩個字節的符號的存儲?謝謝
USC-2只能用存儲兩個字節的Unicode,超過這一範圍的符號,它不能表示。
Annis 說:
我是Annis,想邀請您參加拼搏到底FeedSky博客挑戰賽,
這是一個很好的宣傳、展示自己的機會,
有興趣您可以自己到相關網站了解具體參賽細節。
http://www.feedsky.com/challenge/?u=141270
Bill 說:
PS:本文只是主要介紹了UTF-8編碼,下面這篇文章對於GB碼與Big5有更詳細的介紹。
漢字編碼中現在主要用到的有三類,包括GBK,GB2312和Big5。
1、GB2312又稱國標碼,由國家標準總局發佈,1981年5月1日實施,通行於大陸。新加坡等地也使用此編碼。它是一個簡化字的編碼規範,當然也包括其他的符號、字母、日文假名等,共7445個圖形字符,其中漢字佔6763個。我們平時說6768個漢字,實際上裏邊有5個編碼爲空白,所以總共有6763個漢字。
GB2312規定“對任意一個圖形字符都採用兩個字節表示,每個字節均採用七位編碼表示”,習慣上稱第一個字節爲“高字節”,第二個字節爲“低字節”。GB2312中漢字的編碼範圍爲,第一字節0xB0-0xF7(對應十進制爲176-247),第二個字節0xA0-0xFE(對應十進制爲160-254)。
GB2312將代碼表分爲94個區,對應第一字節(0xa1-0xfe);每個區94個位(0xa1-0xfe),對應第二字節,兩個字節的值分別爲區號值和位號值加32(2OH),因此也稱爲區位碼。01-09區爲符號、數字區,16-87區爲漢字區(0xb0-0xf7),10-15區、88-94區是有待進一步標準化的空白區。
2、Big5又稱大五碼,主要爲香港與臺灣使用,即是一個繁體字編碼。每個漢字由兩個字節構成,第一個字節的範圍從0X81-0XFE(即129-255),共126種。第二個字節的範圍不連續,分別爲0X40-0X7E(即64-126),0XA1-0XFE(即161-254),共157種。
3、GBK是GB2312的擴展,是向上兼容的,因此GB2312中的漢字的編碼與GBK中漢字的相同。另外,GBK中還包含繁體字的編碼,它與Big5編碼之間的關係我還沒有弄明白,好像是不一致的。GBK中每個漢字仍然包含兩個字節,第一個字節的範圍是0x81-0xFE(即129-254),第二個字節的範圍是0x40-0xFE(即64-254)。GBK中有碼位23940個,包含漢字21003個。
Bill再推薦一個網站 專門介紹漢字與漢字計算機化的 漢典 http://www.zdic.net/
簡單 說:
很強的網站,收藏
Ruan YiFeng 說:
引用Bill的發言:本文只是主要介紹了UTF-8編碼,下面這篇文章對於GB碼與Big5有更詳細的介紹。
這篇網誌中有兩個地方需要補充一下,我忘了在原文中提到。
1.
國際標準化組織通過了一套ISO-8859-1的編碼,規定了單字節256個符號的編碼方式。目前,這是8位編碼的國際標準。
2.
Unicode編碼中表示字節排列順序的那個文件頭,叫做BOM(byte-order mark),FFFE和FEFF就是不同的BOM。
UTF-8文件的BOM是“EF BB BF”,但是UTF-8的字節順序是不變的,因此這個文件頭實際上不起作用。有一些編程語言是ISO-8859-1編碼,所以如果用UTF-8針對這些語言編程序,就必須去掉BOM,即保存成“UTF-8—無BOM”的格式纔可以,PHP語言就是這樣。
請教 說:
我怎麼用 notepad 保存成 UTF-8 後
用 UltraEdit 看 還是 FF FE 25 4E啊???
請教 說:
引用請教的發言:我怎麼用 notepad 保存成 UTF-8 後 用 UltraEdit 看 還是 FF FE 25 4E啊???
哦 知道了。 是UltraEdit 默認會以 UTF-16的方式打開UTF-8編碼的文件, 要設置或者用Hex Workshop打開就可以看到樓主所說的效果。
Cloudream 說:
(點擊支持我)
這些字符是違反adsense規定的……
jackywdx 說:
這麼精彩的講解,實在不得不向作者致敬!
內容講解得非常詳細但又通俗易懂,謝謝了~~
jinwangen 說:
非常感謝
LMN 說:
非常感謝,值得一看
網友 說:
標題“6. Unicode與UTF-8之間的轉換”不嚴謹。
Unicode是一種字符集,概念比較抽象,你已經提到,它存儲的時候必須用適當的編碼方式。
你的標題的意思,實際上是UTF-16和UTF-8之間的轉換。
至於windows notepad保存對話框的編碼方式列表中列出“Unicode”這一個名字,實際上是一個通俗的稱呼(來自windows NT的早期版本的習慣,一直沿用),指UTF-16,而不是嚴格的稱呼。希望你行文不要受這個影響。
Ruan YiFeng 說:
引用網友的發言:標題“6. Unicode與UTF-8之間的轉換”不嚴謹。
Unicode是一種字符集,概念比較抽象,你已經提到,它存儲的時候必須用適當的編碼方式。
你的標題的意思,實際上是UTF-16和UTF-8之間的轉換。
UTF-16不等於unicode啊,不能混爲一談。
Ivan WONG 說:
嗯,看完了長不少知識.
Michael Zheng 說:
我只能這麼說,看了那麼多的對字符集的解釋
這個絕對是最通俗易懂並且還解決了常見疑問的最好的文章 :)
收藏
wxs8088 說:
很好的一編文章
人跟人的差距咋就這麼大呢 說:
好文章!收藏了!
樓主何不把ansi編碼方式也說說!
讓俺這樣的小學新生借樓主的理解能力再學習一把.
學習了 說:
學習了
水中魚 說:
引用Ruan YiFeng的發言:UTF-16不等於unicode啊,不能混爲一談。
UTF-16擴充了Unicode,包括了一些稀有字符,想我們國家的滿文,藏文等等,兩者基本上等價
heroboy 說:
其實我認爲,編碼其實有2個意思。1.一個是把字符和數字對應起來(比如unicode和GBXXXX等)。2.還有就是相應在數字在計算機中的表示,也就是和字節序列對應起來(比如utf8,mbcs等)。
我有個問題,windows下的mbcs編碼(2)用的編碼(1)是不是GB系列的編碼(1),而unicode編碼(2)用的是unicode編碼(1)
Demo 說:
拜讀。。。受益匪淺。。長見識了 。。頂樓主
GoBoat 說:
很精彩啊
yangxiups 說:
有時總想去搞清楚他們的區別,可總是無果而終。
講的很通俗。收藏了。
Maxwell 說:
通俗易懂,對樓主的付出表示感謝。
好文章,收藏!
hao 說:
Big endian 是大頭,還是大尾?
gaga 說:
本文充分展現了阮兄收集信息,總結和歸納信息的能力,佩服和學習!
BATMAN 說:
非常感謝樓主提供的信息,支持個
zhangzhen 說:
挺好的,謝謝
陳 說:
謝謝
Texas 說:
非常感謝樓主。
請繼續寫DBCS->UNICODE的文章
riskman 說:
寫得真不錯!!
Taken 說:
感謝阮兄精彩講解...收穫良多
另:能否稍微再增加點UTF-16,UTF-32的基本介紹和應用範圍的介紹...
syjun37 說:
非常感謝這篇文章,我想請問一下,GBK和BIG5之間的關係是怎樣的呢?是包含還是交集呢?
gg 說:
引用syjun37的發言:非常感謝這篇文章,我想請問一下,GBK和BIG5之間的關係是怎樣的呢?是包含還是交集呢?
完全不同的兩套編碼標準,對應不同的代碼頁。同樣的字在big5和GBK中的編碼是不一樣的。
Honeyhacker 說:
相當不錯,這是我打算研究編碼的時候看到的第一篇文章。幾天之後再來評論!!
Honeyhacker 說:
你在文中提到:“UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度”。我在http://dev.csdn.net/develop/article/83/83012.shtm上看到:
以下是Unicode和UTF-8之間的轉換關係表:
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
該文中明顯說到UTF-8不限於四個字節。
請問得到1-4個字節的結論是從哪裏找到的?
Ruan YiFeng 說:
引用Honeyhacker的發言:該文中明顯說到UTF-8不限於四個字節。
請問得到1-4個字節的結論是從哪裏找到的?
早先的規定是,utf-8可以到6個字節。但是,這已經廢除了,目前規定是隻支持4個字節,大於U+001FFFFF的符號utf-8不再支持。具體請參閱wikipedia。
Honeyhacker 說:
原來如此!感謝你的回覆!再問一個問題,從網絡中抓獲的數據報,在用wireshark分析的時候,如何判斷其中的哪些數據使用了Unicode編碼?(從snort給出的信息中,該條數據確實有Unicode編碼)。
morpheus 說:
前輩,計算機怎麼知道三個字節表示一個符號,而不是分別表示三個符號呢
這個是怎麼實現的呢,我有點不明白,還望回覆一下,感激不盡。
Honeyhacker 說:
或者這樣說,兩臺主機通信的時候,A接收到B發送的消息後,它如何知道該報文采取的是什麼編碼類型?在報文的格式裏面好像沒有提到這一點吧!
chen3feng 說:
引用Ruan YiFeng的發言:UTF-16不等於unicode啊,不能混爲一談。
Windows 從 NT 開始,一開始的內碼是 UCS-2,只支持 Unicode BMP 字符,後來做了擴充,目前的內碼就是 UTF-16,通常不嚴格地稱爲 Unicode。
Honeyhacker 說:
引用Honeyhacker的發言:或者這樣說,兩臺主機通信的時候,A接收到B發送的消息後,它如何知道該報文采取的是什麼編碼類型?在報文的格式裏面好像沒有提到這一點吧!
已經弄明白了!不可一概而論!
想 說:
受益匪淺謝謝老師!
挪威的森林 說:
好文!是我看過的關於字符/字符集入門文章中最通俗易懂而又有效的一篇!
wangkai 說:
佩服,不得不頂,一直想搞清楚,今天總算清楚了一點
wangkai 說:
關於第8點:8. 實例
我照着做了,但是結果卻不是這樣,
後面三種方式顯示的都是 FF FE 25 4E
這是怎麼回事?
我用的是vista系統
ArthurLee 說:
通俗易懂,受益匪淺,謝謝指教!O(∩_∩)O~
www 說:
很感謝 寫的很生動 楞看了百度百科半天沒懂。。。
xingyifeng 說:
謝謝
你們的討論很精彩
這樣纔會有長進
手腳冰涼 說:
一直對這些字符集和編碼比較頭疼,今天看了阮兄和大家的討論,終於有點清楚了,謝謝阮兄給大家帶來這麼好的文章。
illidan.zen 說:
通俗易懂,我頂!
sanki 說:
不錯不錯,寫得太棒了!
cocobear 說:
寫得不錯。。
IT民工 說:
>需要注意的是,Unicode只是一個符號集,它只規定了符號的二進制>代碼,卻沒有規定這個二進制代碼應該如何存儲。
>比如,漢字“嚴”的unicode是十六進制數4E25,轉換成二進制數足>足有15位(100111000100101),也就是說這個符號的表示至少需>要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚>至更多。
有一點疑問,unicode編碼使用2個字節也就是16位2進制數字來表示字符,那麼在存儲的時候,爲什麼會超過2個字節以上呢?
unicode所能定義的符號總共有65536個,而且裏面的每一個符號都是用2個字節表示的,包括ascii碼也都是在高位補零的,麻煩樓主解釋一下
vivi 說:
在實例8中,我這裏ASCII碼是D1 CF。但是其它的存儲方式,打開都是顯示 FF FE 25 4E,不論用什麼方式存儲?
jing.lu 說:
非常生動形象,易於理解,很不錯。
xix 說:
太感謝您的文章了,收藏了。
之前也看過幾篇介紹utf8編碼的,但都是語言生硬晦澀的長篇大論,感覺太專業、太複雜,看着頭大。
這篇文章總結的很好,本來繁雜的東東,理得很清晰易懂。感謝!
patric 說:
vivi 說:
在實例8中,我這裏ASCII碼是D1 CF。但是其它的存儲方式,打開都是顯示 FF FE 25 4E,不論用什麼方式存儲?
我操作了,和你說的情況一樣。
2 說:
一知半解,誤人子弟
美麗明天 說:
我想把網站做成韓文的,不知道有什麼好方法.
jhx 說:
謝謝了!
houkai 說:
寫的很通俗 學懂了 謝謝!
goodappli 說:
第一個參考鏈接太難打開了,半天都沒有載入,讓人崩潰,改天再試。
flowsands 說:
阮大有空再來聊聊新字符集國標GB18030吧,Superset of gb2312.
參見:http://en.wikipedia.org/wiki/GB_18030
XjAcKs 說:
原來是這樣,這下更清楚了。謝謝!
allen 說:
感謝,寫的很清楚詳細
htc 說:
寫得太好了,感謝樓主的貢獻
mlmt 說:
正在頭痛這個編碼的事,感謝樓主。
延伸閱讀裏的第一個鏈接是英文.再次證明,學好英文是一件多少重要的事。
Tdou 說:
寫的通俗易懂,謝謝了!
Harly 說:
此文從框架上說明了字符編碼的套路。我見過太多的不明就裏的人,寫這樣的文章,試圖闡明字符編碼系統,但限於其人先天上大腦邏輯混亂,後天上一知半解,結果就是胡說八道,情形就像:分不清class和instance的區別。
azziporah 說:
引用Harly的發言:此文從框架上說明了字符編碼的套路。我見過太多的不明就裏的人,寫這樣的文章,試圖闡明字符編碼系統,但限於其人先天上大腦邏輯混亂,後天上一知半解,結果就是胡說八道,情形就像:分不清class和instance的區別。
非常同意ls的觀點
字符編碼是跨越電子通信和語言文字兩大領域的龐大系統。其一是“編碼”本身,伴隨着電子和通信技術的發展一直在改進,同時也帶來了許多legacy的產物;其二是“字符”,由於人類語言/書寫系統的多樣性和複雜性,將編碼應用到語言文字上來又是一大難題,各種語言文字有各自的出發點和難點。因此,嘗試解決這一混亂局面的UCS/Unicode實在是一項恢弘的工程。無怪乎lz在開頭就說了,這個問題比他想象中複雜。
即使是現在最常見的7-bit ASCII,雖然看上去比較簡單、且有些雜亂無章,實則每個字符的排布都經過了精心的設計,包括性能上的、工程上的、兼容性上的許多考慮因素。
另外,說起字符編碼,就會有許多含糊不清、容易混淆的詞彙,其中很多是基於歷史原因,還有一些以訛傳訛的和巧合的因素,這方面也是需要注意的。
對於大多數人來說,即使您已經系統地學習過數電/計算機課程,我仍然推薦閱讀《編碼的奧祕》。有較好的基礎的人可以參考一下資料
http://scripts.sil.org/Home
http://www.unicode.org/standard/standard.html
http://msdn.microsoft.com/en-us/library/dd318661(v=VS.85).aspx
盜版小米米 說:
形象生動,易於理解!!!!牛
RGLS 說:
非常感謝lz的文章,介紹得很清楚。
樹樹 說:
寫得很好,一直不太明白字符編碼方面的東西
o0o0o 說:
細想起來,可能這是我看到的最好一闡述編碼的文章,精煉易懂,big endian和little endian來源的有趣介紹讓人印象深刻
atom 說:
文章恆久遠,一篇永流傳。感謝阮兄的勞動!
c0ming 說:
big endian和little endian 應該有更好的譯名:大、小端。在網絡編程 和 嵌入式方面都是這樣譯。
落葉 說:
剛研究UNICODE與ASCII之間的轉換工具,突然想到爲啥UTF-8和UNICODE長得這麼像啊,如果Google了一下,看到這篇文章,真的不錯。
yanghe 說:
通俗易懂,支持
frostmoon 說:
正在學習編碼 兄弟的文章通俗易懂 豁然開朗!
javie 說:
奇怪 我的“嚴”的UTF8二進制怎麼都是fffe 254e??
試過記事本 ,emeditor,ultraedit都是
johnw 說:
拜讀了,最近正在弄Java的亂碼問題,看完了明白了很多原理性的東西!
towry 說:
很有幫助啊,謝謝分享。轉到我的QQ空間裏了,慢慢看。
DerekWu 說:
很好,通俗易懂。謝謝。
yuhai 說:
文中所提的大端法和小端法用來描述字節序列問題不夠詳細
zhenyulu 說:
非常好,網上搜了半天資料,還是這篇文章寫得好!
cumirror 說:
很詳細易懂,贊一個~
胡營 說:
看了很多資料都沒看懂,這下懂了!贊一個!o(≧v≦)o~~好棒
evil39c 說:
終於弄懂UTF-8了,謝謝。
ray 說:
以漢字”嚴“爲例,Unicode碼是4E25,需要用兩個字節存儲,一個字節是4E,另一個字節是25。
4E25不是code point嗎?應該是經utf8轉換爲E4B8A5這三個字節才涉及字節序問題吧?
葫蘆 說:
第四、五節不是很好理解。
很棒的文章。
森馬 說:
轉你的博客了,對我很有用。多謝。
另外文中連接的unicode的編碼表裏面數據貌似不對。
小郭 說:
這篇文章真的很棒 謝謝
Lidh 說:
引用Ruan YiFeng的發言:......
UTF-8文件的BOM是“EF BB BF”,但是UTF-8的字節順序是不變的,因此這個文件頭實際上不起作用。有一些編程語言是ISO-8859-1編碼,所以如果用UTF-8針對這些語言編程序,就必須去掉BOM,即保存成“UTF-8—無BOM”的格式纔可以,PHP語言就是這樣。
UTF-8文件的BOM“EF BB BF”,它實際上就是FE FF用UTF-8編碼而得到的
張彥飛 說:
結合最常用的記事本來介紹Unicode,UTF-8. 太好了!!
negatlov 說:
引用網友的發言:windows notepad保存對話框的編碼方式列表中列出“Unicode”這一個名字,實際上是一個通俗的稱呼(來自windows NT的早期版本的習慣,一直沿用),指UTF-16,而不是嚴格的稱呼。希望你行文不要受這個影響。
這個說法很正確。的確換成utf-16準確點。mac osx這上面做得就很好。
negatlov 說:
引用水中魚的發言:
UTF-16擴充了Unicode,包括了一些稀有字符,想我們國家的滿文,藏文等等,兩者基本上等價
記得utf-16是unicode的具體實現方法。你這種說法本來就有混淆概念。
Finals 說:
這個可以用來分段讀取UTF-8字符,不錯
旦旦 說:
藏文最好的那種啊字符編碼?如在QT裏
pw.cheng 說:
非常感謝樓主的講解,我想知道的你說了好多,這個地址收藏了
U雅de凋0 說:
好東西 !謝謝 峯哥 的總結 與 無私奉獻!我不用再 苦苦 搜索了!謝謝
葫蘆 說:
引用chen3feng的發言:
Windows 從 NT 開始,一開始的內碼是 UCS-2,只支持 Unicode BMP 字符,後來做了擴充,目前的內碼就是 UTF-16,通常不嚴格地稱爲 Unicode。
unicode是字符集,UTF-16是編碼方式。。。 不嚴格地成爲Unicode是咋個意思。。
qqtoys 說:
寫得很清楚,非常受用。謝謝作者。
半睡的灰狼 說:
寫的真的挺不錯的! 頂
mm 說:
Windows 7 簡體中文版用的是GBK編碼,兼容GB2312。
殘陽 說:
你好,目前被一個問題困擾。。。
是這樣的,有一被壓縮過的流沒有解壓而直接被轉化成字符串了(當然是亂碼了),這是新浪的一個雲應用FetchURL乾的。。。我看了他們的源碼,直接用apache提供的包中的EntityUitls中的toString方法轉化成字符串了,所以我在發送請求的時候在加上請求頭Accept-Encoding:gzip,他們沒有解壓就直接轉化成字符串了。問題來了,我現在的作法是把這個字符串轉化成字節,然後解壓,具體的作法是:用String類中的getBytes(Charset),然後InputStream in1 = new GZIPInputStream(new ByteArrayInputStream(bytes1)),這裏報錯了,這個bytes1的字節已經不是1f 8b開頭的,也就是說不是壓縮過的模式了,求解。。。爲什麼。。難道EntityUitls,把壓縮過的流轉化爲字符串的時候丟了字節碼,還是什麼情況(這裏有個特例,就是ISO-8859-1可以還原,其餘都不行)。。。
xiaobin 說:
寫的太好了。有個問題想請教下,mysql中是如何用latin1來存中文的。
Daniel 說:
@殘陽:
關於使用ISO-8859-1,我認爲是因爲:
“ISO-8859-1 字符集的編碼範圍是 0000-00FF,正好和一個字節的編碼範圍相對應。這種特性保證了使用 ISO-8859-1 進行編碼和解碼可以保持編碼數值“不變”。雖然中文字符在經過網絡傳輸時,被錯誤地“拆”成了兩個歐洲字符,但由於輸出時也是用 ISO-8859-1,結果被“拆”開的中文字的兩半又被合併在一起,從而又剛好組成了一個正確的漢字。”
具體可以看搜到的這篇blog:
http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
彗星 說:
確實深入淺出,不錯!
爛爛 說:
前幾天才從fanfou看到linus的帖
今天找編碼 就又找到這裏
shuiyouren 說:
非常感謝您的分享,我一直在納悶計算機是如何判斷utf-8中的ascii部分,現在完全清晰了,額,竟然一直沒發現ascii保留了最高位爲0……
icolin 說:
"因此,第一個字節在前,就是”大頭方式“(Big endian),第二個字節在前就是”小頭方式“(Little endian)。
那麼很自然的,就會出現一個問題:計算機怎麼知道某一個文件到底採用哪一種方式編碼?
Unicode規範中定義,每一個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫做”零寬度非換行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。這正好是兩個字節,而且FF比FE大1。
如果一個文本文件的頭兩個字節是FE FF,就表示該文件採用大頭方式;如果頭兩個字節是FF FE,就表示該文件採用小頭方式。"
文中的big endian 和 little endian,翻譯成“大尾”和“小尾”是不是更恰當?理由如下:
FEFF: FF 比 FE大且FF在後面,顯示就是“大尾”
另外你在延伸閱讀中提到的文章也是翻譯成“大尾”和“小尾” (談談Unicode編碼)
Poken-Chen 說:
哈哈,謝謝啊。
我有個私人問題可以問一下嗎?
就是如果有了新字符的話?如何添加到Unicode裏呢?怎麼向Unicode或者國家申請嗎?會通過嗎?
xiekun 說:
我有個疑問“ANSI:文件的編碼就是兩個字節“D1 CF”,這正是“嚴”的GB2312編碼,這也暗示GB2312是採用大頭方式存儲的”
請阮兄指教,不是說用FE,FF來表示大端和小端嗎,爲啥說從上面的編碼可以看出是採用大頭方式的呢
FallenMax 說:
感謝阮老師,和所引用資料的作者。好文,清晰易懂。
情花一衝 說:
我只想說:我很感動,感動樓主的清晰易懂,一天的bug,終於在此貼解決,,,苦逼的程序員,,,想哭 。。。。
xujinnan 說:
這個問題也是我一直想弄清楚的,今天終於找到了篇好的文章,受益匪淺啊,感謝博主!
Homer 說:
感謝樓主!要是大學教材都用這種風格來編寫,估計四年的計算機課程,真正在讀書的1年就夠了!!
utf-8的設計的確很巧妙:“2)對於n字節的符號(n>1),第一個字節的前n位都設爲1【後面有幾個字節兄弟們,就設計幾個的顯示位!計算機首先讀到的,就是應該作爲一組來解析的字節兄弟總數】,第n+1位設爲0【表示顯示位結束!】,後面字節的前兩位一律設爲10【表示這些字節都是被剛纔那個leader領導的兄弟們】……”
另請教一下,對於在128—255的ASCII擴展字符,由於利用了最高位,應該就是與utf-8不一樣了吧?
aisensiy 說:
一直對 utf-8 unicode 很模糊,這篇完整講的太到位了
ChanneW 說:
可是,以ANSI方式保存的文本文檔也能正常顯示中文啊~
David 說:
好早的文章,居然被人推薦過來了,真是很好的科普文章。
關於 UTF-8,它有一個非常好的特性文中應該順帶提一下:雖然不同的字符字節數不同,但是任何一個字符不會是另一個字符的一部分。這使得基於字節的字符串匹配算法可以直接應用在 UTF-8 上。一些新興的語言,如 Go ,字符串處理方面有很大部分是針對 UTF-8 編碼的,個人感覺是空間、執行效率以及編程複雜度比較好的平衡。
峯 說:
很容易理解。
hilojack 說:
引用姬着的發言:文章裏說:UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。
那USC-2編碼方式如何實現超過兩個字節的符號的存儲?謝謝
ucs2不能實現兩字節以上字符,得使用支持4字節的utf16,我的博客 字符編碼入門有提及
千鶴 說:
再看一遍效果又不同了,證明自己沒懂。
leo569 說:
阮老師的文章,絕對值得一讀。以前寫java的,對底層瞭解相對缺失,現在寫C++遇到這類問題極爲棘手。拜讀了
FlyingFish 說:
講得通俗易懂,很明白。謝謝作者!
聞一多 說:
這樣的基礎的東西很好。
小明 說:
好文章,不太長的文章能把事情都說明白,很不簡單。
peach5460 說:
太有幫助了,我以前從沒真正弄懂過字符編碼...
平和的心 說:
有個問題請教一下,Unicode編碼指的是UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。那對於Unicode編碼超過兩個字節的,就沒法保存了?
遊客 說:
引用平和的心的發言:有個問題請教一下,Unicode編碼指的是UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。那對於Unicode編碼超過兩個字節的,就沒法保存了?
還有UCS-4唄,當然UCS-2用的比較多而已,可編碼的漢字也僅僅是個子集而已。
fly 說:
這麼精彩的講解,實在不得不向作者致敬!
內容講解得非常詳細但又通俗易懂,謝謝了~~
apollo 說:
你好,我用uncode保存“嚴”, 用hex查看是:e4 b8 a5 00 c4 00。而後三個字節,00 c4 00會因爲的我保存一直在變化,有的時候會是 00 ee 3e,有的時候直接空了~
我用的win7
後來,經過嘗試,又出現了BOM,顯示爲文中提到的ff fe 25 4e
這種情況最讓人蛋疼了,搞不清是爲什麼~
求教樓主
digdeep126 說:
一直對這一塊沒有完全弄明白,博主真是個打破沙鍋問到底的人。感謝博主的精彩文章。
loli 說:
博主,這事我迄今看過最通俗易懂的 關於編碼的文章了,太感謝了。之前看過其他很多,都是一頭霧水。。
wwj 說:
近期發現您的文章,覺得很多都值得收藏,通俗易懂!非常感謝分享知識和想法
Song 說:
一點小小的問題,有一個地方『根據』的『根』寫爲了『跟』,變成了『跟據』
le 說:
非常感謝。通俗易懂。
share 說:
非常通俗易懂
lan 說:
非常有用,受益匪淺,感謝!
mll 說:
UTF-8的表示算法:既然第一個字節的"1"的數量就表示了整個當前字符的字節數,爲什麼後續字節還需要"10"作爲前綴,這不是白白浪費了每個字節中的兩個位嗎?
xxx 說:
引用mll的發言:UTF-8的表示算法:既然第一個字節的"1"的數量就表示了整個當前字符的字節數,爲什麼後續字節還需要"10"作爲前綴,這不是白白浪費了每個字節中的兩個位嗎?
也許是出於容錯的考慮,網絡傳輸或者兼容不夠不嚴謹的編輯器,刪掉漢字等字節字符中的部分字節,會使得整串字符亂碼
MR.曹 說:
如果早點看到樓主的文章,今天騰訊的實習生筆試就又多一層把握了!
ibuick 說:
破特麼幾吧文章 什麼特麼雞巴玩意兒
ibuick 說:
就這文章水平 我就呵呵了
layoe 說:
感覺博大精深。但依舊受益匪淺。
謝謝lz
文太 說:
博主您好,我認爲第5段表格中關於4字節的UTF-8編碼可表示的 Unicode Code Point 的範圍應該是:
0001 0000-001F FFFF
ppxia 說:
頂一個 講的很透徹。
Liuruoze 說:
感謝樓主的文章,傳道授業解惑也
有點甜 說:
引用mll的發言:UTF-8的表示算法:既然第一個字節的"1"的數量就表示了整個當前字符的字節數,爲什麼後續字節還需要"10"作爲前綴,這不是白白浪費了每個字節中的兩個位嗎?
試想,當你處在一個字符串中間時,你不知道當前是一個什麼字符,使用UTF-8能幫你在這種情況下同步到下一個合法字符,否則是不可能的。
chenjw 說:
謝謝你的精彩分享。但有一個疑問:
"Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符號",我的初步理解是:Unicode既然是2字節的,那麼按理說不會超過256*256個字符纔對。這裏的“100多萬個符號”箇中來由,可否細談下?
柚子 說:
引用chenjw的發言:謝謝你的精彩分享。但有一個疑問:
"Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符號",我的初步理解是:Unicode既然是2字節的,那麼按理說不會超過256*256個字符纔對。這裏的“100多萬個符號”箇中來由,可否細談下?
是的,我也有這個疑問,能否請教樓主,望來信告知![email protected]
柚子 說:
引用xiaobin的發言:寫的太好了。有個問題想請教下,mysql中是如何用latin1來存中文的。
嗯,關於mysql這邊,我也有一個問題。
我這邊有一個mysql是默認的latin1的編碼,我的應用是java寫的,我想:“不管mysql的編碼如何,我只要在java應用對編碼做正確的轉換,那麼就應該能夠在寫入和讀出mysql時不出現亂碼纔對。”,請問這個想法是否正確呢?
dlitchi 說:
引用柚子的發言:是的,我也有這個疑問,能否請教樓主,望來信告知![email protected]
阮大哥的文章有說過哦,傳送門:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
Brilliance 說:
引用chenjw的發言:謝謝你的精彩分享。但有一個疑問:
"Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符號",我的初步理解是:Unicode既然是2字節的,那麼按理說不會超過256*256個字符纔對。這裏的“100多萬個符號”箇中來由,可否細談下?
unicode是字符集, 不是存儲方式, 這個搞明白.
通常所說2個字節的unicode實際上是指utf-16, 這應該是winnt遺留下來的叫法. 實際上unicode包括8位,16位,32位等存儲方式. 其中u8和u32都可以最多用4Byte表示一個字符. 而u16最多用2Byte表示.
遊客 說:
【USC-2只能用存儲兩個字節的Unicode,超過這一範圍的符號,它不能表示。】
這個說法是錯誤的。記事本的ucs-2存儲方式類同於utf-16的存儲方式。
林錦 說:
引用chenjw的發言:謝謝你的精彩分享。但有一個疑問:
"Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符號",我的初步理解是:Unicode既然是2字節的,那麼按理說不會超過256*256個字符纔對。這裏的“100多萬個符號”箇中來由,可否細談下?
Unicode的編碼空間從U+0000到U+10FFFF,共有1,112,064個碼位(code point)可用來映射字符. Unicode的編碼空間可以劃分爲17個平面(plane),每個平面包含216(65,536)個碼位。
17個平面的碼位可表示爲從U+xx0000到U+xxFFFF,其中xx表示十六進制值從0016到1016,共計17個平面。(Plane 0,1,2,....9,a,b,c,d,e,f,10)
第一個平面稱爲基本多語言平面(Basic Multilingual Plane, BMP),或稱第零平面(Plane 0)。其他平面稱爲輔助平面(Supplementary Planes)。
基本多語言平面內,從U+D800到U+DFFF之間的碼位區段是永久保留不映射到Unicode字符。UTF-16就利用保留下來的0xD800-0xDFFF區段的碼位來對輔助平面的字符的碼位進行編碼。
淘魚 說:
好文章就是好文章,都過了這麼多年,我不記得了還是來找這篇文章看看。07年到14年
goldenshaw 說:
最近在寫編碼方面的一個系列,搜到這裏來了,感覺文中對Unicode及UTF-8這兩個不同層面還是沒說透,可參考我已經寫好的一些http://my.oschina.net/goldenshaw/blog?catalog=536953,講得比較詳細。
另:文中說記事本用的所謂Unicode是UCS-2,其實早就應該是UTF-16了,至少我的系統裏已經是UTF-16,而不是什麼UCS-2,UCS-2只有兩字節,根本無法保存U+FFFF以上碼點的字符。
九地之方 說:
嗯,雖然有些名詞概念講的不是很清楚,但通俗易懂,還算不錯。
其實博主着重過的語句主要是講字符集和字符編碼關係,例如:“UTF-8是Unicode的實現方式之一”這句話,Unicode就是字符集,它規定一個字符對應的編碼,比如博主說的“嚴”對應的編碼是4E25。而UTF-8是字符編碼,它規定在內存中應該以怎樣的方式來存儲4E25,類似的對應Unicode字符集的字符編碼還有UTF-16等。
最後補充下博主說的大端序(BE)和小端序(LE):每個字節內的比特位不會受大端和小端的影響,例如20H,在大端和小端中的內存順序都是00100000。
Ruyi 說:
總結的太好了,節省了好多時間,非常感謝你!
Victor 說:
引用ChanneW的發言:可是,以ANSI方式保存的文本文檔也能正常顯示中文啊~
ANSI(注意拼寫不是ASCII)並不是“一種”編碼,而是“多種”編碼的統稱。在簡體中文Windows上,ANSI指GBK編碼;在繁體中文Windows上,ANSI指Big5編碼;在英文Windows上,ANSI指cp437編碼。
jack 說:
如果UTF8無BOM的情況下,程序應如何識別呢?
yanhaijing 說:
正需要
monklof 說:
阮一峯老是說:
UTF-8的編碼規則很簡單,只有二條:
1)對於單字節的符號,字節的第一位設爲0,後面7位爲這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
2)對於n字節的符號(n>1),第一個字節的前n位都設爲1,第n+1位設爲0,後面字節的前兩位一律設爲10。剩下的沒有提及的二進制位,全部爲這個符號的unicode碼。
其中第2點,對於n字節的符號的理解是不是有偏差呢?
再看具體的編碼:
Unicode符號範圍 | UTF-8編碼方式
(十六進制) | (二進制)
--------------------+---------------------------------------------
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
其中Unicode 0080~07FF段 和 Unicode 0800~FFFF段都是兩個字節,卻不適用於第2)條 規則的。
就像它的名字都表示的
改成
就像它的名字所表示的
許湘涵 說:
很不錯 好文章就是解惑有啓發
揚空 說:
醍醐灌頂
胡曉曉 說:
還沒看完就趕緊過來留言了,感謝博主,這就是我關心的問題,哈哈,給你個贊。
Ray 說:
寫的太好了.找了好多篇文章,峯哥的這篇深入淺出,讓我止不住的想盲目膜拜一下.
mihooke 說:
嗯!Comments ,wonderfully!
CiBai 說:
對我的幫助很大。。謝謝你。。。
朱國偉 說:
你好, 請教一個問題。 已讓我寢食難安好幾天了。如下所示:
mysql會話中執行status:
Server characterset: latin1
Db characterset: latin1
Client characterset: latin1
Conn. characterset: latin1
表結構:
CREATE TABLE `t3` (
`data` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
mysql> insert into t3 select '嚴';
mysql> select data,hex(data) from t3;
+------+-----------+
| data | hex(data) |
+------+-----------+
| 嚴 | E4B8A5 |
+------+-----------+
奇怪! 不是latin1嗎?怎麼和utf8沒有區別呢?
icesnow 說:
我也正在做一個編碼的轉換,請問如何將ansi編碼轉換成utf-8編碼呢?
我曾經試着手動把unicode編碼轉換爲Utf-8編碼就是簡單地遍歷所有的字節數組,然後把0和1刪除。不知道這樣做對嗎?
現在問題是怎麼把ansi編碼轉成utf-8呢?
或者把ansi編碼轉成完全是字節數組的十六進制表示?
chengbapi 說:
原文:
Unicode符號範圍 | UTF-8編碼方式
(十六進制) | (二進制)
--------------------+---------------------------------------------
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
最後一行應該是 0001 0000-001F FFFF
您的大名 說:
"UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號"
應該是1~6個字節
OnePiece 說:
請允許我叫你阮兄,哈哈,雖然我才大一計算機專業的學生,不過很喜歡看阮兄你的文章
曉薇 說:
unicode編碼轉utf8編碼js實現,代碼感覺寫的不是很好,看到可以簡化一下,
var unicodeToUTF8 = function(unicode) {
if(unicode >= 0x00000000 && unicode return unicode;
}
else if(unicode >= 0x00000080 && unicode var r1 = (((unicode & 0x7C0) >> 6)|0xC0) var r2 = (unicode & 0x03F)|0x80;
return r1 | r2;
}
else if(unicode >= 0x00000800 && unicode var r1 = (((unicode & 0xF000) >> 12)|0xE0) var r2 = (((unicode & 0x0FC0) >> 6)|0x80) var r3 = ((unicode & 0x003F)|0x80);
return r1 | r2 | r3;
}
else if(unicode >= 0x00010000 && unicode var r1 = (((unicode & 0x1C0000) >> 18)|0xE0) var r2 = (((unicode & 0x03F000) >> 12)|0x80) var r3 = (((unicode & 0x000FC0) >> 6)|0x80) var r4 = ((unicode & 0x00003F)|0x80);
return r1 | r2 | r3 | r4;
}
else {
return false;
}
}
楊傑 說:
寫的真的是通俗易懂,深入淺出,很讓我這樣的小白受益啊。感謝感謝
Jason 說:
"EF BB BF" 這個是windows的text editor添加的BOM,用其他的編輯器不一定會出現。
hoho 說:
已知"嚴"的unicode是4E25(100111000100101),根據上表,可以發現4E25處在第三行的範圍內(0000 0800-0000 FFFF)這個是啥意思?怎麼對應起來的?
jingmi 說:
感謝作者的講解,通俗易懂!看過明白很多。
wier 說:
引用柚子的發言:
是的,我也有這個疑問,能否請教樓主,望來信告知![email protected]
統一碼的編碼方式與ISO 10646的通用字符集概念相對應。目前實際應用的統一碼版本對應於UCS-2,使用16位的編碼空間。也就是每個字符佔用2個字節。這樣理論上一共最多可以表示216(即65536)個字符。基本滿足各種語言的使用。實際上當前版本的統一碼並未完全使用這16位編碼,而是保留了大量空間以作爲特殊使用或將來擴展。
上述16位統一碼字符構成基本多文種平面。最新(但未實際廣泛使用)的統一碼版本定義了16個輔助平面,兩者合起來至少需要佔據21位的編碼空間,比3字節略少。但事實上輔助平面字符仍然佔用4字節編碼空間,與UCS-4保持一致。未來版本會擴充到ISO 10646-1實現級別3,即涵蓋UCS-4的所有字符。UCS-4是一個更大的尚未填充完全的31位字符集,加上恆爲0的首位,共需佔據32位,即4字節。理論上最多能表示231個字符,完全可以涵蓋一切語言所用的符號。
基本多文種平面的字符的編碼爲U+hhhh,其中每個h代表一個十六進制數字,與UCS-2編碼完全相同。而其對應的4字節UCS-4編碼後兩個字節一致,前兩個字節則所有位均爲0。
關於統一碼和ISO 10646及UCS的詳細關係,見通用字符集。
維基百科上,有輔助平面字符
奧丁1號 說:
通俗易懂
劉晉霞 說:
受益匪淺
心聲 說:
您好,非常感謝,真的是通俗易懂,果然是大神
發現文章中有個地方寫差了:
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
應該是:
0001 0000-001F FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
再次感謝。
sigh 說:
文中
```
Unicode符號範圍(十六進制) | UTF-8編碼方式(二進制)
--------------------|---------------------------------------------
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
```
的最後一行應該爲
```
Unicode符號範圍(十六進制) | UTF-8編碼方式(二進制)
--------------------|---------------------------------------------
0000 0000 - 0000 007F | 0xxxxxxx
0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 001F FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
```
kiscms 說:
1、Unicode符號範圍的最大值爲什麼是 0X10FFFF ?
2、0X10FFFF 的二進制是 00010000 11111111 11111111 ,很明顯它是三個字節的,那麼對應轉成utf8的規則就是1110xxxx 10xxxxxx 10xxxxxx ,可是爲什麼文中要對應成 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx,我想知道,這張表是按什麼規律生成的?
Zack 說:
清晰,易懂。
Lemon 說:
講得簡潔易懂,棒
張鼕鼕 說:
感謝博主!最近在解決java用jni調用C++中的一些編碼方式問題,這篇文章深入淺出、講解得清晰又易懂!幫了我大忙了,又學了些知識
Neo 說:
真難想象博主在07年就整理出這詳盡的計算機文檔, 在零散的互聯網知識裏面你的 Blog最能激發我認真閱讀的興趣! :)
博主崇拜者 說:
經典,通俗易懂,條例清晰。
博主崇拜者 說:
好的文章,十年後有人看了都會忍不住回覆。
alias 說:
文章通俗易懂,贊
-_-宋宋-_- 說:
知識果然不易過時,收藏~~
Weiting 說:
非常有用的文章!! 謝謝你~~
伯格 說:
老師好,下面這句話我應該怎麼理解呢?
《這裏就有兩個嚴重的問題,第一個問題是,如何才能區別Unicode和ASCII?計算機怎麼知道三個字節表示一個符號,而不是分別表示三個符號呢?》
既然不同的編碼會用不同的編碼解讀,那麼怎麼會出現不能區分Unicode和ASCII的問題?我用ASCII解讀不就可以了嗎?
所以我太懂這個問題的怎麼出現的?
Asun 說:
看過老師很多文章,每一篇都是好文,感謝老師分享
chappie 說:
引用伯格的發言:老師好,下面這句話我應該怎麼理解呢?
《這裏就有兩個嚴重的問題,第一個問題是,如何才能區別Unicode和ASCII?計算機怎麼知道三個字節表示一個符號,而不是分別表示三個符號呢?》既然不同的編碼會用不同的編碼解讀,那麼怎麼會出現不能區分Unicode和ASCII的問題?我用ASCII解讀不就可以了嗎?
所以我太懂這個問題的怎麼出現的?
用unicode編碼的文件,所有的字符都用兩個字節編碼,ASCII也是,所以不會存在這個區分的問題
Jixuan Cheng 說:
你太有教育人的天賦了。我現在編程有不明白的地方,如果是基礎的不理解,就找你的網來讀!都能明白!真棒!謝謝
mccasey 說:
參考這個utf8編碼對照表更清晰,來自https://en.wikipedia.org/wiki/UTF-8
Number Bit for first last
of bytes code points code points code points Byte 1 Byte 2 Byte 3 Byte 4
1 7 U+0000 U+007F 0xxxxxxx
2 11 U+0080 U+07FF 110xxxxx 10xxxxxx
3 16 U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 21 U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
hk4fun 說:
http://www.cnblogs.com/leesf456/p/5317574.html
劉江龍 說:
讀了你很多文章了,這篇也有收穫。 這個例子做了一個unicode到UTF-8字符集的掩碼運算,mark到這裏備忘。
漢字 嚴的 unicode碼點 4E25
0100 1110 0010 0101
1110 xxxx 10xx xxxx 10xx xxxx
1110 0100 1011 1000 1010 0101
汗青 說:
謝謝分享,真的很感謝,願意分享的自己知識的人都是好樣的!
wsj 說:
1,
ascii碼由美國人發明,長度爲一個字節,8個二進制,最長表示256個字符,
標準的ascii爲128個,前面一個bit爲0,用後面7位表示128個ascii碼。
2,
爲了兼容世界所有字符,重新編了一套Unicode,每個符號給予獨一無二的編碼,
現在可容納100多萬字符,這就意味着Unicode的編碼變得特別多,也就不可能用1個
字節表示ASCII嗎,因爲解碼的時候所有比特連在一起,會將你本來用來表示ascii碼的
一個字節混淆(因爲unicode編碼太多,此ascii的編碼可能與Unicode某個編碼中的某
一段重複);所以必須加長用來表示ascii的編碼,以進行區別,但這就帶來一個浪費內
存的問題。
3,
所以出現了utf8,它用前N+1個比特表示它的長度N(除了單字節是用一個0比特表示,這時
的utf8編碼與ascii編碼一致,都是一個字節),後面的編碼直接從Unicode編碼裏面拿。所以它
不是全新的編碼,是Unicode的一種實現方式,相比而言節省了內存(尤其是在以英文居多的時候)。
wyq 說:
在這篇文章剛好十年的時候看到了。。。
xxx 說:
10 year anni
HeroTimor 說:
十年後來看一下,當時阮哥的博客略顯青澀哦。
noans 說:
引用心聲的發言:您好,非常感謝,真的是通俗易懂,果然是大神
發現文章中有個地方寫差了:
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx應該是:
0001 0000-001F FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx再次感謝。
UTF-8的最大值之所以是 10FFFF 而不是 1FFFFF 是因爲Unicode的範圍是 U+0-10FFFF
下面的鏈接是Unicode的範圍設置原因討論的帖子
http://unicode.org/mail-arch/unicode-ml/Archives-Old/UML021/0881.html
小張 說:
每個字符在Unicode裏面的位置是一定的,爲什麼不能直接使用這個位置進行二進制存儲呢,也能做到動態大小存儲吧?
會飛小超人 說:
最近在找字符編碼的文章,看了好幾篇,果然還是阮老師的最清晰易懂!
我要發表看法
您的留言 (HTML標籤部分可用)
您的大名:
«-必填
電子郵件:
«-必填,不公開
個人網址:
«-我信任你,不會填寫廣告鏈接
記住個人信息?
«- 點擊按鈕
2018 © 我的郵件 |