日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

字符集与字符编码详解

發(fā)布時間:2024/1/3 综合教程 33 生活家
生活随笔 收集整理的這篇文章主要介紹了 字符集与字符编码详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

字符

字符和字節(jié)不太一樣,任何一個文字或符號都是一個字符,但是所占字節(jié)不一定,不同的編碼導致一個字符所占的內(nèi)存不同。

例如:標點符號"+"是一個字符,漢字"我們"是兩個字符,在GBK編碼中一個漢字占2個字節(jié),在UTF-8編碼中一個漢字占3個字節(jié)。

隨著時代的發(fā)展,程序員們希望在計算機中顯示字符,但計算機只能識別0和1的二進制數(shù)。于是就有了編碼規(guī)范。

編碼規(guī)范

所謂的字符集其實是一套編碼規(guī)范中的子概念,為了顯示字符,國際組織就指定了編碼規(guī)范,希望使用不同的二進制數(shù)來表示代表不同的字符,這樣電腦就可以根據(jù)二進制數(shù)來顯示其對應的字符。我們通常就稱呼其為xx編碼,xx字符集。

例如:GBK 編碼規(guī)范,根據(jù)這套編碼規(guī)范,計算機就可以在中文字符和二進制數(shù)之間相互轉(zhuǎn)換。而使用GBK編碼就可以使計算機顯示中文字符。

編碼規(guī)范里的3個子概念:

1、字庫表

一套編碼規(guī)范不一定包含世界上所有的字符,每套編碼規(guī)范都有自己的使用場景。而字庫表就存儲了編碼規(guī)范中能顯示的所有字符,計算機就是根據(jù)二進制數(shù)從字庫中找到字符然后顯示給用戶,相當于一個存儲字符的數(shù)據(jù)庫。

例如:幾乎所有漢字都保存在GBK編碼規(guī)范的字庫表中。所以可以顯示漢字,但法語、俄語并不在其字庫表中,所以GBK不能顯示法語、俄語等不包含在其中的字符。

2、編碼字符集(字符集)

在一個字庫表中,每一個字符都有一個對應的二進制地址,而編碼字符集就是這些地址的集合。字符集和字庫表一一對應,相互轉(zhuǎn)換,這是電腦識別字符的關(guān)鍵。

如果把世界上不同國家文明的所有字符都放在一起組成一個集合,那么我們常見的 ASCII、GB2312、GBK、GB18030、BIG5 字符集都只是包含了該集合的一部分而已。而Unicode字符集是可以包含所有國家文明中的所有字符的。

3、字符編碼(編碼方式)

知道字庫表編碼字符集后,我們就可以直接使用二進制地址來得到字符了。但直接使用字符對應的二進制地址來顯示文字是十分浪費的,Unicode 編碼規(guī)范中包括了幾百萬個字符,想要包括幾百萬個不同的字符,起碼需要3個字節(jié)的容量,為了方便將來擴展,Unicode還保留了更多未使用的空間,最多可以存儲4個字節(jié)的容量。

因此為了區(qū)分每個字符,哪怕是00000000 00000000 00000000 00001111這種其實只占了一個字節(jié)的字符,我們也要為它分配4個字節(jié)的空間,這就導致一個可以用1G保存的文件,現(xiàn)在需要4G才能保存,這是極其浪費的做法。

于是程序員就定下了一套算法來節(jié)省空間,而每種不同的算法都被稱作一種編碼方式一套編碼規(guī)范可以有多種不同的編碼方式,不同的編碼方式有不同的適應場景。例如:UTF-8就是一種編碼方式,Unicode是一種編碼規(guī)范。此外Unicode還有UTF-16、UTF-32這兩種編碼方式。不同的編碼方式節(jié)約的空間不同。總結(jié):一個較短的二進制數(shù),通過一種編碼方式,轉(zhuǎn)換成編碼字符集中正常的地址,然后在字庫表中找到一個對應的字符,最終顯示給用戶。

ASCII編碼

計算機一開始發(fā)明的時候是用來解決數(shù)字計算的問題,后來人們發(fā)現(xiàn),計算機還可以做更多的事,例如文本處理。但由于計算機只識"數(shù)",因此人們必須告訴計算機哪個數(shù)字來代表哪個特定字符,例如65代表字母'A',66代表字母'B',以此類推。但是計算機之間字符-數(shù)字的對應關(guān)系必須得一致,否則就會造成同一段數(shù)字在不同計算機上顯示出來的字符不一樣。因此美國國家標準協(xié)會ANSI制定了一個標準,規(guī)定了常用字符的集合以及每個字符對應的編號,這就是ASCII字符集(Character Set)也稱ASCII碼(American Standard Code for Information Interchange,美國信息交換標準代碼)。

ISO-8859-1編碼

為了表示更多的歐洲等國家使用的字符,對原始的ASCII編碼范圍進行了擴充,采用一個字節(jié)256種不同狀態(tài)來表示256種不同的字符。ISO-8859-1編碼是單字節(jié)編碼,向下兼容ASCII,它的編碼范圍使用了單字節(jié)內(nèi)的所有空間(即8位,0-255),在支持ISO-8859-1的系統(tǒng)中傳輸和存儲其他任何編碼的字節(jié)流都不會被拋棄。換言之,把其他任何編碼的字節(jié)流當作ISO-8859-1編碼看待都沒有問題。這是個很重要的特性,MySQL數(shù)據(jù)庫默認編碼是Latin1就是利用了這個特性。ASCII編碼是一個7位的容器,ISO-8859-1編碼是一個8位的容器。

多字節(jié)字符集(MBCS)和中文字符集

上面我們提到的字符集都是基于單字節(jié)編碼,也就是說一個字節(jié)翻譯成一個字符,這對于拉丁語系國家來說足夠了。但是對于亞洲國家來說,256個字符是遠遠不夠用。因此在保持和ASCII字符集的兼容下,就發(fā)明了多字節(jié)編碼方式,相應的字符集就稱為多字節(jié)字符集。對于單字節(jié)字符集來說,代碼頁中只需要有一張碼表即可,上面記錄著256個數(shù)字代表的字符,程序只需要做簡單的查表操作就可以完成編解碼的過程。對于多字節(jié)字符集,代碼頁中通常會有很多碼表,根據(jù)第一個字節(jié)來選擇不同的碼表進行解析。

目前最常用的中文字符集GB2312,涵蓋了所有簡體字符以及一部分其他字符;GBK則在GB2312的基礎上加入了對繁體字符等其他非簡體字符。GBK字符集中所有字符占2個字節(jié),不論中文英文都是2個字節(jié)。從ASCII、GB2312到GBK,這些編碼方法是向下兼容的,即同一個字符在這些方案中總是有相同的編碼,后面的標準支持更多的字符。在這些編碼中,英文和中文可以統(tǒng)一地處理。區(qū)分中文編碼的方法是高字節(jié)的最高位不為0。GB2312、GBK都屬于雙字節(jié)字符集(DBCS)

ANSI標準、國家標準、ISO標準

不同ASCII衍生字符集的出現(xiàn),會讓文檔交流變得非常困難。如美國ANSI組織制定了ANSI標準字符編碼,ISO組織制定的各種ISO標準字符編碼,還有各國也會制定一些國家標準字符集,例如中國的GBK,GB2312和GB18030。

操作系統(tǒng)在發(fā)布的時候,通常會往機器里預裝這些標準的字符集還有平臺專用的字符集,這樣只要你的文檔是使用標準字符集編寫的,通用性就比較高了。例如你用GB2312字符集編寫的文檔,在中國大陸內(nèi)的任何機器上都能正確顯示。同時,我們也可以在一臺機器上閱讀多個國家不同語言的文檔了,前提是本機必須安裝該文檔使用的字符集。

Unicode的出現(xiàn)

雖然通過使用不同字符集,我們可以在一臺機器上查閱不同語言的文檔,但是我們?nèi)匀粺o法解決一個問題:在一份文檔中顯示所有字符。為了解決這個問題,我們需要一個全人類達成共識的巨大的字符集,這就是Unicode字符集。Unicode簡稱為UCS。Unicode字符集涵蓋了目前人類使用的所有字符,并為每個字符進行統(tǒng)一編號,分配唯一的字符碼(Code Point)。Unicode字符集將所有字符按照使用上的頻繁度劃分為17個層面(Plane),每個層面上有2^16=65536個字符碼空間。其中第0個層面BMP,基本涵蓋了當今世界用到的所有字符。其他的層面要么是用來表示一些遠古時期的文字,要么是留作擴展。我們平常用到的Unicode字符,一般都是位于BMP層面上的。

在Unicode出現(xiàn)之前,所有的字符集都是和具體編碼方案綁定在一起的,都是直接將字符和最終字節(jié)流綁定死了。例如ASCII編碼系統(tǒng)規(guī)定使用7比特來編碼ASCII字符集;GB2312以及GBK字符集,限定了使用最多2個字節(jié)來編碼所有字符,并且規(guī)定了字節(jié)序。這樣的編碼系統(tǒng)通常用簡單的查表,也就是通過代碼頁就可以直接將字符映射為存儲設備上的字節(jié)流了。這種方式的缺點在于,字符和字節(jié)流之間耦合得太緊密了,從而限定了字符集的擴展能力。因此Unicode在設計上考慮到了這一點,將字符集和字符編碼方案分離開。

例如同樣是對Unicode字符"A"進行編碼,UTF-8字符編碼得到的字節(jié)流是0x41,而UTF-16(大端模式)得到的是0x00 0x41。UCS只是規(guī)定如何編碼,并沒有規(guī)定如何傳輸、保存這個編碼,關(guān)鍵在于通信雙方都要認可。UTF是"UCS Transformation Format"的縮寫。

UCS-2、UCS-4

UCS有兩種格式:UCS-2和UCS-4。UCS-2就是用兩個字節(jié)編碼,它有2^16=65536個碼位,UCS-4就是用4個字節(jié)編碼(實際上只用了31位,最高位必須為0),它有2^31=2147483648個碼位。對于Unicode來說,UCS-2和UCS-4是字符碼(內(nèi)碼)。

UTF-8

UTF-8編碼方案采用1-4個字節(jié)來編碼字符,對于ASCII字符的編碼使用單字節(jié),和ASCII編碼一摸一樣。對于其他字符,則使用2-4個字節(jié)來表示。其中首字節(jié)前置1的數(shù)目代表正確解析所需要的字節(jié)數(shù),剩余字節(jié)的高2位始終是10。例如首字節(jié)是1110xxxx,前置有3個1說明正確解析總共需要3個字節(jié),需要和后面2個以10開頭的字節(jié)結(jié)合才能正確解析得到字符。

如上表所示,對于只需要1個字節(jié)的字符,UTF-8采用ASCII碼的編碼方式,最高位補0來表示。例如:01000001我們就是用01000001來表示,對于一個字節(jié)的字符,其實就是直接使用地址表示。而對于n個字節(jié)的字符(n>1),即大于一個字節(jié)的字符,采用第一個字節(jié)前n位補1。第n+1位填0,后面字節(jié)的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的unicode字符碼。

例如:漢字嚴的Unicode碼是4E25轉(zhuǎn)換成二進制就是0100111000100101,根據(jù)上表可知使用UTF-8字符編碼后占3個字節(jié),因此前3位是1,第4位(n+1位)是0,后面兩個字節(jié)中每個字節(jié)的前兩位都是10,即1110 xxxx 10 xxxxxx 10 xxxxxx。填充進去后就變成了1110 0100 10 11100010 100101共計24位占3個字節(jié)。

由此可見,英文在UTF-8字符編碼后只占1個字節(jié),中文占了3個字節(jié)

帶簽名的UTF-8

帶簽名指的是字節(jié)流以BOM標記開始。很多軟件會"智能"地探測當前字節(jié)流使用的字符編碼,這種探測過程出于效率考慮,通常會提取字節(jié)流前面若干個字節(jié),看看是否符合某些常見字符編碼的編碼規(guī)則。由于UTF-8和ASCII編碼對于純英文的編碼是一樣的,無法區(qū)分開來,因此通過在字節(jié)流最前面添加BOM標記可以告訴軟件,當前使用的是Unicode編碼,判別成功率就十分準確了。但是需要注意,不是所有軟件或者程序都能正確處理BOM標記,例如PHP就不會檢測BOM標記,直接把它當普通字節(jié)流解析了。因此如果你的PHP文件是采用帶BOM標記的UTF-8進行編碼的,那么有可能會出現(xiàn)問題。

UTF-16

UTF-16 是介于 UTF-8 和 UTF-32 之間,使用2個或者4個字節(jié)來存儲的,其長度即固定又可變。

UTF-32

UTF-32 是固定長度的編碼,始終占用 4 個字節(jié),足以容納所有的 Unicode 字符。所以直接存儲 Unicode 編號即可,不需要任何編碼轉(zhuǎn)換。浪費了空間,提高了效率。

GB18030

任何能夠?qū)nicode字符映射為字節(jié)流的編碼都屬于Unicode編碼。中國的GB18030編碼,覆蓋了Unicode所有的字符,因此也算是一種Unicode編碼。只不過他的編碼方式并不像UTF-8或者UTF-16一樣,將Unicode字符的編號通過一定的規(guī)則進行轉(zhuǎn)換,而只能通過查表的手段進行編碼。

GBK、GB2312等與UTF-8之間都必須通過Unicode編碼才能相互轉(zhuǎn)換:

GBK、GB2312 -- Unicode字符碼 -- UTF-8

UTF-8 -- Unicode字符碼 -- GBK、GB2312

字節(jié)序

計算機硬件有兩種儲存數(shù)據(jù)的方式:大端字節(jié)序(big endian)和小端字節(jié)序(little endian)

大端字節(jié)序:高位字節(jié)在前,低位字節(jié)在后,這是人類讀寫數(shù)值的方法。

小端字節(jié)序:低位字節(jié)在前,高位字節(jié)在后。

舉例來說:0x1234567的大端字節(jié)序和小端字節(jié)序的寫法如下

為什么會有小端字節(jié)序?計算機電路先處理低位字節(jié),效率比較高,因為計算都是從低位開始的。所以計算機的內(nèi)部處理都是小端字節(jié)序。但是人類還是習慣讀寫大端字節(jié)序,所以除了計算機的內(nèi)部處理,其他的場合幾乎都是大端字節(jié)序,比如網(wǎng)絡傳輸和文件儲存。

計算機處理字節(jié)序的時候,不知道什么是高位字節(jié),什么是低位字節(jié)。它只知道按順序讀取字節(jié),先讀第一個字節(jié),再讀第二個字節(jié)。如果是大端字節(jié)序,先讀到的就是高位字節(jié),后讀到的就是低位字節(jié)。小端字節(jié)序正好相反。所以只有在讀取的時候,才必須區(qū)分字節(jié)序,其他情況都不需要考慮。處理器讀取外部數(shù)據(jù)的時候,必須知道數(shù)據(jù)的字節(jié)序,將其轉(zhuǎn)成正確的值。然后,就正常使用這個值,完全不用再考慮字節(jié)序。即使是向外部設備寫入數(shù)據(jù),也不用考慮字節(jié)序,正常寫入一個值即可。外部設備會自己處理字節(jié)序的問題。

大小端

計算機界對于傳輸多字節(jié)字(由多個字節(jié)來共同表示一個數(shù)據(jù)類型)時,是先傳高位字節(jié)(大端)還是先傳低位字節(jié)(小端)也有著不一樣的看法。無論是寫文件還是網(wǎng)絡傳輸,實際上都是往流設備進行寫操作的過程,而且這個寫操作是從流的低地址向高地址開始寫。對于多字節(jié)字來說,如果先寫入高位字節(jié),則稱作大端模式。反之則稱作小端模式。也就是說,大端模式下,字節(jié)序和流設備的地址順序是相反的,而小端模式則是相同的。一般網(wǎng)絡協(xié)議都采用大端模式進行傳輸。

關(guān)于亂碼

亂碼指的是程序顯示出來的字符文本無法用任何語言去解讀。造成亂碼的原因就是因為使用了錯誤的字符編碼去解碼字節(jié)流。當程序使用特定字符編碼解析字節(jié)流的時候,一旦遇到無法解析的字節(jié)流時,就會用?或者?來替代。因此,一旦你最終解析得到的文本包含這樣的字符,而你又無法得到原始字節(jié)流的時候,說明正確的信息已經(jīng)徹底丟失了,嘗試任何字符編碼都無法從這樣的字符文本中還原出正確的信息來。

總結(jié)

經(jīng)過上邊的介紹,我們可以大致認為,現(xiàn)在流行的一些編碼方案都是在兼容ASCII的基礎上來實現(xiàn)的。為了滿足各國家地區(qū)的更多字符的編碼需求,出現(xiàn)了ANSI編碼標準,但是該編碼標準在具體各地區(qū)國家的實現(xiàn)上是彼此不兼容的。為了滿足世界各國字符編碼的兼容性需求,Unicode定義了一個統(tǒng)一、完備的字符集。為了實現(xiàn)Unicode字符集在編碼上的需求,又誕生了UTF-8、UTF-16等等編碼方案。

總結(jié)

以上是生活随笔為你收集整理的字符集与字符编码详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。