博客 / 詳情

返回

簡述字符集與編碼

由於計算機內部只能識別和處理二進制代碼,所以字符都必須按照一定的規則用一組二進制編碼來表示。

在學習編碼之前,需要先了解一下 字符集與編碼的關係:
字符集(Character Set)是字符的集合,定義系統能處理哪些字符;編碼(Encoding)則規定這些字符在計算機內部的表示方式。

image

字符編碼ASCII碼(編碼字符集)

目前,國際上普遍採用的一種字符系統是7位二進制編碼的ASCII碼,它可表示10個十進制數碼、52 個英文大寫字母和小寫字母(A~Z, a~z)及一定數量的專用符號(如$、%、+、=等),共128個字符。為了存入計算機,通常最高位補0,湊足1B。

在ASCII碼中,編碼值0~31為控制字符,用於通信控制或設備的功能控制;編碼值32~126共95個字符稱為可印刷字符;編碼值127是DEL碼。

0~9的ASCII碼值為48(0110000)~57(0111001),即去掉高3位,只保留低4位,正好是二進制形式的0-9。

由於ASCII碼的侷限性,各國的語言不能完整地表示出來。於是對 ASCII 字符集做了拓展。


漢字的表示和編碼

目前採用 GB 2312-80標準 : 漢字+各種符號共7445個。用兩個字節表示一個漢字,每字節用七位碼。(1個漢字相當於兩個英文字符)

規定:ASCII 值小於 127 的字符的意義與原來 ASCII 集中的字符相同,但當兩個 ASCII 值大於 127 的字符連在一起時,就表示一個簡體中文的漢字。

為了在解碼時操作的統一,在 ASCII 裏本來就有的數字、標點、字母都統一重新表示為了兩個字節長的編碼,這就是常説的 “全角” 字符,而原來在 127 號以下的就叫 “半角” 字符。

漢字編碼包括:

  • 輸入編碼

    • 區位碼
    • 國標碼
  • 漢字內碼
  • 漢字字形碼

區位碼:94個區,每區94個位置。是4位十進制數,前2位是區碼,後2位是位碼。
國標碼:將十進制的區位碼轉換成十六進制數後,再在每字節上加上20H。國標碼兩字節的最高位都是0。
漢字內碼:為了方便計算機區分中文字符和英文字符,將國標碼兩字節最高位都改為“1“,這就是漢字內碼。

GBK

GBK 是對 GB2312 的一個擴展,兼容 GB2312,因此也兼容 ASCII,也是一個變長編碼方案。下面是一個簡介:

GBK 總體編碼範圍為 8140-FEFE,首字節在 81-FE 之間,尾字節在 40-FE 之間,總計 23940 個碼位,共收入 21886 個漢字和圖形符號,其中漢字(包括部首和構件)21003 個,圖形符號 883 個。

GBK 是國家有關部門與一些信息行業企業等一起合作推出的方案,但並未作為國家標準發佈,只是一個事實上的標準,一個過渡方案,為 GB18030 標準作的一個準備。


世界上各國都有不同的編碼方式,0—127 表示的符號依然都是一樣的,因為他們都兼容 ASCII 碼,但127之後的同一個二進制數字可以被解碼成不同的符號。因此,要想打開一個文本文件,就必須知道它的編碼方式,否則用錯誤的編碼方式解讀,就會出現亂碼。


Unicode

把所有語言都統一到一套編碼裏,且兼容 ASCII。

ASCII、GBK 等類編碼模式的字符集和編碼方式都是一一對應的,Unicode是字符集,UTF-32/ UTF-16/ UTF-8是三種字符編碼方案。

整個編碼可分為兩個過程。首先,將程序中的字符根據字符集中的編號數字化為某個特定的數值,然後根據編號以特定的方式存儲到計算機中。

編號就相當於 ASCII 碼中的 ASCII 值,它就是 Unicode 字符集中唯一表示某個字符的標識,在 Unicode 也稱作碼點(Code Point)

image

碼點轉換成各種編碼,又涉及到編碼過程中定長變長兩種實現方式,UTF-32 就屬於定長編碼,即永遠用 4 字節存儲碼點,而 UTF-8、UTF-16 就屬於變長存儲,UTF-8 根據不同的情況使用 1-4 字節,而 UTF-16 使用 2 或 4 字節來存儲碼點。

UTF-32

在 UTF-32 這種定長的編碼方式下就表示每 4 個子節一個斷句,那麼字符 A 的碼點 U+0041(二進制為 1000001)被 UTF-32 編碼後就會變成如下形式存儲在計算機中:

00000000 00000000 00000000 01000001

它會將 4 個字節中空出的高位全部填充為 0。這種表示的最大缺點是佔用空間太大,因為不管都大的碼點都需要四個字節來存儲,非常的佔空間,那麼如何突破這個瓶頸呢?變長方案應運而生。

UTF-8

UTF-8 屬於變長的編碼方式,它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。使用的是高位保留的方式來區別不同變長,具體方式如下:

  1. 對於單字節的符號,字節的第一位設為0,後面7位為這個符號的 Unicode 碼。因此對於英語字母,UTF-8 編碼和 ASCII 碼是相同的。
  2. 對於n字節的符號(n > 1),第一個字節的前n位都設為1,第n + 1位設為0,後面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的 Unicode 碼。

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,就表示當前字符佔用多少個字節,”醜” 有三個 1 表示佔三個字符,然後取出有效位即可。

Emoji

Unicode 為 Emoji 分配碼點。 Emoji 符號就是一個文字,它會被渲染為圖形。

Emoji編碼


以上三種都是屬於文字的編碼,但在計算機中,還有類似圖片這種媒體資源。因為圖片的二進制編碼中包含有很多不可見字符,無法用文本展示。


Base64

base64編碼是用來解決把不可打印的內容塞進可打印內容的需求的。比如把圖片存到數據庫,圖片數據歸根到底還是一堆二進制串,用base64編碼後的顯示成的字符串就大大縮小的長度,可以存到數據庫。

所謂Base64,就是:小寫字母a-z、大寫字母A-Z、數字0-9、符號"+"、"/"(再加上作為墊字的"=",實際上是65個字符)----作為一個基本字符集。然後,其他所有符號都轉換成這個字符集中的字符。

具體來説,轉換方式可以分為四步。

第一步,將每三個字節作為一組,一共是24個二進制位。
第二步,將這24個二進制位分為四組,每個組有6個二進制位。
第三步,在每組前面加兩個00,擴展成32個二進制位,即四個字節。
第四步,根據下表,得到擴展後的每個字節的對應符號,這就是Base64的編碼值。

因為,Base64將三個字節轉化成四個字節,因此Base64編碼後的文本,會比原文本大出三分之一左右。

如果字節數不足三,則這樣處理:

1.二個字節的情況:將這二個字節的一共16個二進制位,按照上面的規則,轉成三組,最後一組除了前面加兩個0以外,後面也要加兩個0。這樣得到一個三位的Base64編碼,再在末尾補上一個"="號。

比如,"Ma"這個字符串是兩個字節,可以轉化成三組00010011、00010110、00010000以後,對應Base64值分別為T、W、E,再補上一個"="號,因此"Ma"的Base64編碼就是TWE=。

2.一個字節的情況:將這一個字節的8個二進制位,按照上面的規則轉成二組,最後一組除了前面加二個0以外,後面再加4個0。這樣得到一個二位的Base64編碼,再在末尾補上兩個"="號。

比如,"M"這個字母是一個字節,可以轉化為二組00010011、00010000,對應的Base64值分別為T、Q,再補上二個"="號,因此"M"的Base64編碼就是TQ==。

轉換Base64工具
參考文章

計算機中通用的字符編碼的工作方式

在計算機內存中,統一使用Unicode編碼,當需要保存到硬盤或者需要傳輸的時候,就轉換為UTF-8編碼。

瀏覽網頁的時候,服務器會把動態生成的Unicode內容轉換為UTF-8再傳輸到瀏覽器。

Web 中的編碼

要正確顯示HTML頁面,web瀏覽器必須知道頁面中使用的字符集。

<!-- html -->
<meta charset="UTF-8">
​
<!-- xml -->
<?xml version="1.0" encoding="UTF-8"?>

比較HTML和xml中的寫法:xml的寫法更加規範

  • charset 是 character set 的簡寫,即字符集
  • encoding 是 charset encoding 的簡寫,即字符集編碼,簡稱編碼

指定了編碼,它所對應的字符集自然就指定了,編碼才是我們最終要關心的。

如何確定一個網頁中編碼

  1. 文檔內的編碼聲明

    image

  2. 響應體中的content-type字段中的編碼信息

    image

  3. BOM

    BOM=Byte Order Mark,“字節順序標識”。響應流中的開頭字節。

    如果有 BOM,就能直接知道對應的編碼

    img

  4. 缺省

    缺省方式是以上幾種方式都失效時的兜底方案,沒有 BOM,沒有 header,沒有 meta,瀏覽器只好“蒙”一個編碼。

如果多方式並存,且給出的編碼信息不一致,通常按這樣的優先級來取捨:

BOM > 響應頭編碼 > 文檔內編碼聲明

HTML 編碼

在 HTML 中,某些字符是預留的,比如不能使用小於號(<)和大於號(>),這是因為瀏覽器會誤認為它們是標籤。如果希望正確地顯示預留字符,我們必須在 HTML 源代碼中使用字符實體(character entities)。

字符實體: // <
​
& entity_name; // &lt;
或
& entity_number; // &#60;

URI 編碼

編碼原因:

考慮到 URI 在各種平台間傳輸時的兼容性,URI 規範中規定只有 US-ASCII 字符集中的字符可以直接出現在 URI 中。事實上,甚至 ASCII 本身的許多字符也不允許直接出現在 URI 中,有的也要轉義。URL 路徑中的中文需要轉義,具體編碼用的是 utf-8。

可以直接使用的: 26 個大小寫字母,10 個數字,四個標點符號:-._~(“短橫”、“點號”、“下劃線”、“波浪線”)。其它的有的屬於保留字,用作為分隔符(delimiters),它們有:

":" / "/" / "?" / "#" / "[" / "]" / "@" / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

比如正斜槓“/”就是一個最常用的分隔符。如果想在 URL 中包含這樣符號,又不想它們被解析為分隔符,就要對其轉義。其它的還有一些不可以打印的字符也要轉義,比如“空格”等。

保留字符在不做分隔符或者具有特殊含義的時候是需要編碼的。如果使用了一些其他文字和特殊字符,則需要通過編碼的方式來進行表示:

%編碼

由於 URI 在協議中只挑選了部分ASCII 字符,數字以及符號,那麼當需要表示不在這個範圍之內的符號,字符,或者該字符在 URI 中被用來分隔符等特殊用途時,就需要對這個字符進行%編碼。百分號編碼也可以叫做URLEncode,其中的每一個部分用【%XX】來表示,其中 XX 表示一個十六進制的數。

encodeURI 會將需要編碼的字符轉換為 UTF-8 的格式。對於非轉義字符以及保留字符(;,/?:@&=+$#)不會進行轉義。

// URL中包含中文
encodeURI('http://www.帥.com'); // http://www.%E5%B8%85.com
​
// 值的內容為特殊符號。值為?&
encodeURI('http://a.com?key=?&'); // "http://a.com?key=?&"

encodeURIComponent 會編碼所有的 URL 保留字:

encodeURIComponent('https://aotu.io/')
// "https%3A%2F%2Faotu.io%2F"
​
encodeURI('https://aotu.io/')
// "https://aotu.io/"

在處理頁面跳轉、跟服務器端進行交互時, 凡涉及到對URI進行解析的、最好用encodeURIComponent進行編碼避免部分數據的丟失.

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.