WEB開發中的字符集和編碼

2021-09-07 08:06:00 字數 4097 閱讀 7659

我相信很多人在初接觸程式設計時,都被字符集狠狠地虐過,特別是資料庫的中文亂碼問題,那麼亂碼是怎麼產生的呢? 我們都知道計算機是以二進位制儲存和執行的,那麼它是怎麼把二進位制資料轉換為各種文字的呢? 還有我們常用的各種字符集,常用的編碼轉換,都是怎麼進行的呢?

本博文所寫的內容不是技術乾貨,只是對我們常用的字符集和編碼的乙個小總結,小科普。我相信讀完本文,您應該對 字符集和常見編碼方式 有個差不多的認識了。

ascii碼(american standard code for information interchange,美國資訊交換標準**)應該是我們最初接觸過的編碼方式了,程式設計最常用的字元都被它包括在內。它使用7bit來表示 128(2e7)個字元,最高位固定為 0,共占用乙個位元組。其中:

我們會發現這些中很多都可以在鍵盤上可以找得到。

tips:

美國人發明了計算機,並將他們最常用的字元以乙個位元組存入了計算機,可是世界上這麼多的語言都要用計算機來表示怎麼辦呢?

為了使計算機支援多種語言,不同的國家和地區制定了不同的標準。而對於漢字,產生了 gb2312、 big5、 jis 等各自的編碼標準。這些使用 1 個位元組表示乙個英文本元, 2 個位元組來代表乙個字元的各種漢字延伸編碼方式,稱為 ansi 編碼。

我們在使用window系統儲存檔案選擇編碼方式時,會看到有這個ansi編碼這個選項,在不同的windows系統中,ansi代表著不同的編碼。不同ansi編碼之間互不相容,當資訊在國際間交流時,無法將屬於兩種語言的文字,儲存在同一段 ansi 編碼的文字中。

既然ansi編碼有著不同編碼之間互不相容不能共存的缺點,而現代網路中又會頻繁出現多語言互動,如果在多語言網路傳播時,乙個 '11011011' 到底代表著什麼字元呢?

這時,unicode 應運而生,它是乙個足夠大的字元編碼對映表,將所有字元都囊括其中,每乙個都對應唯一乙個 unicode 數值。如漢字 '好' 對應的 unicode 數值為 '0x597d', 轉為二進位制為 '0101 1001 0111 1101',表示它需要 16 bit,兩個位元組,當然還有需要更多位元組來儲存的字元(原諒我舉起不來粟子)。

最新的ucs-4標準是乙個尚未填充完全的31位 unicode 字符集,它使用 31 位來儲存字元,加上恒為 0 的首位,共需佔據 32 位,4 位元組。這樣,unicode 便能儲存 2e31 個字元,已經完全足夠儲存世界上所有的字元了。

tips:

注意 unicode 只是一種符號集,字元儲存的具體實現方式看下面

我們知道了按照 unicode 的標準,儲存乙個字元最多要使用 4 個位元組。如果所有的字元都按照這個標準來儲存,那麼歐美國家可能要哭了,因為他們本來可以用乙個位元組輕鬆儲存文件的,因為國際化,所有的儲存空間要增大三倍。為了解決這個問題,utf-8(8-bit unicode transformation format)出現了。

utf-8採用變長的編碼方式,使用 1~4 個位元組來表示乙個符號:

於是,皆大歡喜,utf-8 成為了網際網路使用最廣泛的 unicode 編碼實現方式。

除此之外,unicode 還有utf-7、punycode、cesu-8、scsu、utf-32、gb18030 等實現方式;

utf8mb4 並不是 unicode 的實現方式之一,它是 mysql 的編碼方式,在最新的 mysql 中,utf8mb4 已經可以代替 utf8,並具有 utf8 不具有的特點。

mb4, 即 most bytes 4, mysql 的 utf8 編碼最多使用 3 個位元組儲存乙個字元,在儲存 4 位元組字元的時候會報錯,而 utf8mb4 最多可以使用4個位元組來儲存乙個字元。所以它可以用來儲存更多的 unicode 字元,包括一些 emoji 表情(emoji 是一種特殊的 unicode 編碼,常見於 ios 和 android 手機上),和很多不常用的漢字,以及任何新增的 unicode 字元。

由於 utf8mb4 為 utf8 的超集,所以 utf8 編碼的 mysql 資料庫可以平滑過渡到 utf8mb4。

url 編碼是 web 開發中最常用的編碼了。由於 url 中一些字元有特殊的作用,那麼它被稱為保留字元(reserved purpose),如 = 用來賦值, ? 用來表示 query_string 的開始, # 用來標識錨點。當我們僅僅想把這些字元當作普通字串傳輸該怎麼辦呢,這就需要使用 url 編碼。

轉換規則:

首先需要把該字元的 ascii 的值表示為兩個十六進製制的數字,然後在其前面放置轉義字元( % ),置入 uri 中的相應位置;對於非 ascii 字元(如中文等), 需要轉換為 utf-8 位元組序, 然後每個位元組按照上述方式表示。

下表是常見的字元和 urlencode 之後的 標識:

char

urlchar

urlchar

urlchar

urlchar

url!

%21#

%23$

%24&

%26'

%27(

%28)

%29*

%2a+

%2b,

%2c/

%2f:

%3a;

%3b=

%3d?

%3f@

%40[

%5b]

%5d tips: php中使用urlencode()urldecode()進行 url 的編碼和解碼。

base64 也是一種 web 開發中的常用編碼,它能實現簡單的可逆加密,同時在系統之間傳輸二進位制等字元使用 base64 編碼也很方便。

它使用a-z a-z 0-9 + /等 64 (2e6) 個字元來表示字元。嚴格來說,還有用來標識結尾處分組的位元組數的=, 它只會出現在編碼串的最後。

將乙個字串以分為三個位元組(3 * 8 = 24 bit)為乙個分組, 將此 24 個 bit 分為四組,每組 6 bit, 然後使用 其 6 bit 對應的十進位制數來對映出乙個 base64 字元;

如 utf-8(三個位元組表示乙個中文) 中文 『琪』 轉 base64 的過程為

十進位制對應 base64 編碼的 對映表如下:

那麼乙個字串拆分到最後不足三位元組了怎麼辦呢?

由於原來三個位元組的字元最後轉換成四個位元組來表示,base64 編碼後字串長度一般為原來 的 3/4。

以下是我為了完全了解 base64 編碼自己用 php 實現的乙個 base64 編碼類(寫完編碼犯懶了。。。):

<?php 

class base64

/*** 將二進位制字串分組後對映為對應的base64字串

** @param $bin_str

** @return string

*/private function bintobase64($bin_str)

$order = base_convert($bin, 2, 10);

}return $base64_str;

}/**

* 將十六進製制字串轉換為二進位制字串

** @param $hex

** @return string

*/private function hextobin($hex)

$bin_str .= $bin;

}return $bin_str;

}}$encoder = new base64();

var_dump($encoder->encode('枕邊書blog')); // 5p6v6l655lmmymxvzw==

var_dump(base64_encode('枕邊書blog')); // 5p6v6l655lmmymxvzw==

tips: 在 php 中使用base64_encode()base64_decode()進行 base64 編碼和解碼。

字符集和編碼一般不是 web 開發中的重點,但了解一下也挺有意思的,既能增長見識,還能預防哪一天突然踩了其中的坑。

參考:阮一峰:字元編碼筆記:ascii,unicode和utf-8

維基百科:unicode

base64筆記

Web開發字符集

本文件旨在說明字符集對於web開發必需掌握的常規應用知識。對於乙個頁面而言,最核心的三個字符集存在於1,檔案編碼 page encode 2,頁面meta資訊 meta 3,http headers裡的content type裡的字符集指定 content type 4,頁面輸出編碼 output ...

字符集和字符集編碼詳解

gb2312 gbk ascii asni unicode utf 8等等,這些字眼非常常見,同時帶來許多的問題。本文只是從理解的角度,說明以上內容的不同含義從而達到區分其用法的目的是夠了的。至於實現方式,可以查閱各自的詳細標準官方文件。先解釋乙個概念,什麼是字符集,嗯,不解釋了,我弄乙個吧 從今以...

字符集和編碼

什麼是字元?字元就是文字和符號的統稱,字符集就是多個字元的集合,字符集有很多種,常見的有ascii,gb2312,unicode字符集。什麼是編碼?計算機要準確的處理字符集中的文字,就需要對字元進行編碼。對unicode字符集編碼的叫做unicode編碼,對ascii字符集編碼叫做ascii編碼。a...