字符集和URL的編碼與解碼

目錄

一、字符集

 1、ASCII碼

ISO-8859-1

2、GBK等各國編碼誕生

3、Unicode誕生——字符集

4、UTF-8誕生——字符編碼

擴展資料UTF-8\UTF-16\UTF-32

二、URL的編碼與解碼

1、哪些字符需要編碼

(1)保留字符

(2)不安全字符

2、如何對Url中的非法字符進行編碼


一、字符集

字符集(Charset):是一個系統支持的所有抽象字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。常見字符集名稱:ASCII字符集、GB2312字符集、GB18030字符集、Unicode字符集等。計算機要準確的處理各種字符集文字,需要進行字符編碼,以便計算機能夠識別和存儲各種文字。

字符編碼的作用

計算機只認識0和1組成的二進制序列,因此任何文件中的內容要想被計算機識別或者想存儲在計算機上都需要轉換爲二進制序列。那麼字符與二進制序列怎麼進行想換轉換呢?於是人們嘗試建立一個表格來存儲一個字符與一個二進制序列的對應關係

編碼 將字符轉換爲對應的二進制序列的過程叫做字符編碼

解碼 將二進制序列轉換爲對應的字符的過程叫做字符解碼

字符集和字符編碼

字符集和字符編碼不是一個概念:字符集定義了文字和二進制的對應關係,爲字符分配了唯一的編號,而字符編碼規定了如何將文字的編號存儲到內存中。有的字符集在制定時就考慮到了編碼的問題,是和編碼結合在一起的;有的字符集只管制定字符的編號,至於怎麼編碼,是其他人的事情。

字符集爲每個字符分配了一個唯一的編號,通過這個編號就能找到對應的字符。在編程過程中我們經常會使用字符,而使用字符的前提就是把字符放入內存中,毫無疑問,放入內存中的僅僅是字符的編號,而不是真正的字符實體。

 1、ASCII碼

最早建立這個字符與十進制數字對應的關係的是美國,這張表被稱爲ASCII碼(American Standard Code for Information Interface, 美國標準信息交換代碼)。ASCII碼是基於拉丁字母的一套電腦編程系統,主要用於顯示現代英語和其他西歐語言。它被設計爲用1個字節來表示一個字符,所以ASCII碼錶最多隻能表示2**8=256個字符。實際上ASCII碼錶中只有128個字符,剩餘的128個字符是預留擴展用的。

ISO-8859-1

既然ASCII只能表示128個字符,顯示是不能完全表示完的,所以ISO-8859-1擴展了ASCII編碼,在ASCII編碼之上又增加了西歐語言、希臘語、泰語、阿拉伯語、希伯來語對應的文字符號,它是向下兼容ASCII編碼的。

ISO-8859-1也是單字節編碼,但它是一個8位的容器,它能表示256個字符。Latin1是ISO-8859-1的別名,有些環境下寫作Latin-1。

2、GBK等各國編碼誕生

隨着計算機的普及和發展,很過國家都開始使用計算機。大家發現ASCII碼預留的128個位置根本無法存儲自己國家的文字和字符,因此各個國家開始制定各自的字符編碼表,其中中國的的字符編碼表有GB2312和GBK。

GB2312 最早一版的中文編碼,每個字佔據2bytes。由於要和ASCII兼容,那這2bytes最高位不可以爲0了(否則和ASCII會有衝突)。在GB2312中收錄了6763個漢字以及682個特殊符號,已經囊括了生活中最常用的所有漢字。

GBK 是GB2312的擴展。GBK中在保證不和GB2312、ASCII衝突(即兼容GB2312和ASCII)的前提下,用每個字佔據2bytes的方式又編碼了許多漢字。經過GBK編碼後,可以表示的漢字達到了20902個,另有984個漢語標點符號、部首等。值得注意的是這20902個漢字還包含了繁體字。

GB18030是GBK的擴展,增加加了幾千個新的少數民族的文字。這時候顯然只用2bytes表示一個字已經不夠用了(2bytes最多隻有65536種組合,然而爲了和ASCII兼容,最高位不能爲0就已經直接淘汰了一半的組合,只剩下3萬多種組合無法滿足全部漢字要求)。因此GB18030多出來的漢字使用4bytes編碼。

字符集兼容圖示:

3、Unicode誕生——字符集

後來隨着世界互聯網的形成和發展,各國的人們開始有了互相交流的需要。但是這個時候就存在一個問題,每個國家所使用的字符編碼表都是不同的。這個時候,人們希望有一個世界統一的字符編碼表來存放所有國家所使用的文字和符號,這就是Unicode。Unicode又被稱爲 統一碼、萬國碼、單一碼,它是爲了解決傳統的字符編碼方案的侷限性而產生的,它爲每種語言中的每個字符設定了統一併且爲之一的二進制編碼。Unicode規定所有的字符和符號最少由2個字節(16位)來表示,所以Unicode碼可以表示的最少字符個數爲2**16=65536。

特點:

定長存儲, 將所有語言都統一到一套編碼集,通常使用2個字節,有的是4個字節。收錄很全。

分爲17個面,基本面採用2個字節,普通中文子也在基本面中,另外16個面是4個字節。

不兼容ASCII碼即存儲的時候,對ASCII碼前面補0,導致存儲的數據變大。

Unicode 是一個獨立的字符集,它並不是和編碼綁定的。

4、UTF-8誕生——字符編碼

爲什麼已經有了Unicode還要UTF-8呢?這是由於當時存儲設備是非常昂貴的,而Unicode中規定所有字符最少要由2個字節表示。人們認爲像原來ASCII碼中的字符用1個字節就可以了,因此人們決定創建一個新的字符編碼來節省存儲空間UTF-8是對Unicode編碼的壓縮和優化,它不在要求最少使用2個字節,而是將所有字符和符號進行分類:

  • ascii碼中的內容用1個字節保存
  • 歐洲的字符用2個字節保存
  • 東亞的字符用3個字節保存
  • ...

UTF-8 是目前互聯網上使用最廣泛的一種 Unicode 編碼方式它的最大特點就是可變長。它可以使用 1 - 4 個字節表示一個字符,根據字符的不同變換長度

UTF-8以字節爲單位對Unicode進行編碼,對不同範圍的字符使用不同長度的編碼。UTF-8兼容ASCII碼

擴展資料UTF-8\UTF-16\UTF-32

UTF 是 Unicode Transformation Format 的縮寫,意思是“Unicode轉換格式”,後面的數字表明至少使用多少個比特位(Bit)來存儲字符。

Unicode 可以使用的編碼有三種,分別是:

  • UFT-8:一種變長的編碼方案,使用 1~6 個字節來存儲;
  • UFT-32:一種固定長度的編碼方案,不管字符編號大小,始終使用 4 個字節來存儲;
  • UTF-16:介於 UTF-8 和 UTF-32 之間,使用 2 個或者 4 個字節來存儲,長度既固定又可變。

UTF-8

UTF-8 的編碼規則很簡單:如果只有一個字節,那麼最高的比特位爲 0;如果有多個字節,那麼第一個字節從最高位開始,連續有幾個比特位的值爲 1,就使用幾個字節編碼,剩下的字節均以 10 開頭。

具體的表現形式爲:

  • 0xxxxxxx:單字節編碼形式,這和 ASCII 編碼完全一樣,因此 UTF-8 是兼容 ASCII 的;
  • 110xxxxx 10xxxxxx:雙字節編碼形式;
  • 1110xxxx 10xxxxxx 10xxxxxx:三字節編碼形式;
  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字節編碼形式。

xxx 就用來存儲 Unicode 中的字符編號。

下面是一些字符的編碼實例(綠色部分表示本來的 Unicode 編號):

對於常用的字符,它的 Unicode 編號範圍是 0 ~ FFFF,用 1~3 個字節足以存儲,只有及其罕見,或者只有少數地區使用的字符才需要 4~6個字節存儲。

UTF-32

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

UFT-16

UFT-16 比較奇葩,它使用 2 個或者 4 個字節來存儲。

對於 Unicode 編號範圍在 0 ~ FFFF 之間的字符,UTF-16 使用兩個字節存儲,並且直接存儲 Unicode 編號,不用進行編碼轉換,這跟 UTF-32 非常類似。

對於 Unicode 編號範圍在 10000~10FFFF 之間的字符,UTF-16 使用四個字節存儲,具體來說就是:將字符編號的所有比特位分成兩部分,較高的一些比特位用一個值介於 D800~DBFF 之間的雙字節存儲,較低的一些比特位(剩下的比特位)用一個值介於 DC00~DFFF 之間的雙字節存儲。

如果你不理解什麼意思,請看下面的表格:

位於 D800~0xDFFF 之間的 Unicode 編碼是特別爲四字節的 UTF-16 編碼預留的,所以不應該在這個範圍內指定任何字符。如果你真的去查看 Unicode 字符集,會發現這個區間內確實沒有收錄任何字符。

UTF-16 要求在制定 Unicode 字符集時必須考慮到編碼問題,所以真正的 Unicode 字符集也不是隨意編排字符的。

總結:只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因爲它們沒有單字節編碼。

參考博文:https://blog.csdn.net/guxiaonuan/article/details/78678043

如果你希望查看完整的 Unicode 字符集,以及各種編碼方式,請猛擊:https://unicode-table.com/cn/

二、URL的編碼與解碼

通常如果一樣東西需要編碼,說明這樣東西並不適合傳輸。原因多種多樣,如Size過大,包含隱私數據。對於Url來說,之所以要進行編碼,是因爲Url中有些字符會引起歧義

例如:Url參數字符串中使用key=value鍵值對這樣的形式來傳參,鍵值對之間以&符號分隔,如/s?q=abc&ie=utf-8。如果你的value字符串中包含了=或者&,那麼勢必會造成接收Url的服務器解析錯誤,因此必須將引起歧義的&和=符號進行轉義,也就是對其進行編碼。

Url的編碼格式採用的是ASCII碼,而不是Unicode,這也就是說你不能在Url中包含任何非ASCII字符,例如中文。否則如果客戶端瀏覽器和服務端瀏覽器支持的字符集不同的情況下,中文可能會造成問題。

Url編碼的原則就是使用安全的字符(沒有特殊用途或者特殊意義的可打印字符)去表示那些不安全的字符。

1、哪些字符需要編碼

RFC3986文檔規定,Url中只允許包含英文字母(a-zA-Z)、數字(0-9)、-_.~4個特殊字符以及所有保留字符。RFC3986文檔對Url的編解碼問題做出了詳細的建議,指出了哪些字符需要被編碼纔不會引起Url語義的轉變,以及對爲什麼這些字符需要編碼做出了相應的解釋。

US-ASCII字符集中沒有對應的可打印字符:Url中只允許使用可打印字符。US-ASCII碼中的10-7F字節全都表示控制字符,這些字符都不能直接出現在Url中。同時,對於80-FF字節(ISO-8859-1),由於已經超出了US-ACII定義的字節範圍,因此也不可以放在Url中。

(1)保留字符

Url可以劃分成若干個組件,協議、主機、路徑等。有一些字符(:/?#[]@)是用作分隔不同組件的。例如:冒號用於分隔協議和主機,/用於分隔主機和路徑,?用於分隔路徑和查詢參數,等等。還有一些字符(!$&'()*+,;=)用於在每個組件中起到分隔作用的,如=用於表示查詢參數中的鍵值對,&符號用於分隔查詢多個鍵值對。當組件中的普通數據包含這些特殊字符時,需要對其進行編碼。

RFC3986中指定了以下字符爲保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]

(2)不安全字符

有一些字符,當他們直接放在Url中的時候,可能會引起解析程序的歧義。這些字符被視爲不安全字符,原因有很多。

  • 空格:Url在傳輸的過程,或者用戶在排版的過程,或者文本處理程序在處理Url的過程,都有可能引入無關緊要的空格,或者將那些有意義的空格給去掉。
  • 引號以及<>:引號和尖括號通常用於在普通文本中起到分隔Url的作用
  • #:通常用於表示書籤或者錨點
  • %:百分號本身用作對不安全字符進行編碼時使用的特殊字符,因此本身需要編碼
  • {}|\^[]`~:某一些網關或者傳輸代理會篡改這些字符

需要注意的是,對於Url中的合法字符,編碼和不編碼是等價的,但是對於上面提到的這些字符,如果不經過編碼,那麼它們有可能會造成Url語義的不同。因此對於Url而言,只有普通英文字符和數字,特殊字符$-_.+!*'()還有保留字符,才能出現在未經編碼的Url之中。其他字符均需要經過編碼之後才能出現在Url中。

注:但是由於歷史原因,目前尚存在一些不標準的編碼實現。例如對於~符號,雖然RFC3986文檔規定,對於波浪符號~,不需要進行Url編碼,但是還是有很多老的網關或者傳輸代理會進行編碼。

2、如何對Url中的非法字符進行編碼

Url編碼通常也被稱爲百分號編碼(Url Encoding,also known as percent-encoding)是因爲它的編碼方式非常簡單,使用%百分號加上兩位的字符——0123456789ABCDEF——代表一個字節的十六進制形式。Url編碼默認使用的字符集是US-ASCII。例如a在US-ASCII碼中對應的字節是0x61,那麼Url編碼之後得到的就是%61,我們在地址欄上輸入http://g.cn/search?q=%61%62%63,實際上就等同於在google上搜索abc了。又如@符號在ASCII字符集中對應的字節爲0x40,經過Url編碼之後得到的是%40。

對於非ASCII字符,需要使用ASCII字符集的超集進行編碼得到相應的字節,然後對每個字節執行百分號編碼。對於Unicode字符,RFC文檔建議使用utf-8對其進行編碼得到相應的字節,然後對每個字節執行百分號編碼。如"中文"使用UTF-8字符集得到的字節爲0xE4 0xB8 0xAD 0xE6 0x96 0x87,經過Url編碼之後得到"%E4%B8%AD%E6%96%87"。

如果某個字節對應着ASCII字符集中的某個非保留字符,則此字節無需使用百分號表示。例如"Url編碼",使用UTF-8編碼得到的字節是0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81,由於前三個字節對應着ASCII中的非保留字符"Url",因此這三個字節可以用非保留字符"Url"表示。最終的Url編碼可以簡化成"Url%E7%BC%96%E7%A0%81" ,當然,如果你用"%55%72%6C%E7%BC%96%E7%A0%81"也是可以的。

注:由於歷史的原因,有一些Url編碼實現並不完全遵循這樣的原則。

參考博文:https://blog.csdn.net/yin554393109/article/details/7343022

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章