字符編碼小結

前言

i 數字編碼

在計算機的世界中,只有0和1,計算機如何能表示無窮無盡的數值呢?人們約定,以8個bit作爲一個字節,以4個字節作爲一組,用於標識int,這樣一來,int就可以表示具有32位0,1組成的二進制數字了,計算機在處理數字的過程中,以每32個bit(4個字節)爲一組進行解析,得到一個二進制數字,在需要供人閱讀時,在將二進制轉換爲10進制,這樣計算機就能表示我們熟悉的10進制數字了。

這個過程中,我們約定了使用4個字節表示int,在計算機內部就可以每4字節解析一個數字,並且約定計算機內部表示的是2進制數字,計算機展示數字時需要將二進制轉換爲10進制供人閱讀,

這裏的兩個約定,就是人們在計算機世界中對整數的編碼,(當然,真實的整數編碼遠比這複雜,這裏不展開討論),可以使用四個字節表示數字,自然也就可以使用其他字節數表示數字,這樣一來,計算機就可以使用不同的字節數對二進制進行解析,得到不同的數值,而使用幾個字節進行解析,就依賴於人們的約定

ii 字符編碼

數字可以通過由10進制轉換爲2進制的方式在計算機內部使用0,1表示,但是字符怎麼辦呢?遇到新問題的時候,最簡單的方法就是將其轉換爲我們已經解決過得問題,可不可以將其轉換爲數字呢?畢竟數字其實也是一種符號而已。

在計算機的發明地美國,第一批使用計算機的人約定了一張映射表,將他們使用的字符映射爲數字,而數字我們是知道的,可以通過二進制表示,從而在計算機中進行使用。這就是ASCII碼,(詳細內容後面細說)

這裏從字符到數字的映射,其實就是我們所說的字符編碼
在這裏插入圖片描述
圖片來自ASCII碼對照表

一、字符編碼的歷史

1.1 第一臺計算機

1946年,第一臺計算機在美國賓夕法尼亞大學誕生。發明人是美國人莫克利(JohnW.Mauchly)和艾克特(J.PresperEckert),美國國防部用它來進行彈道計算。它是一個龐然大物,用了18000個電子管,佔地150平方米,重達30噸,耗電功率約150千瓦,每秒鐘可進行5000次運算,這個算力在今天看來也許微不足道,但是在當時卻是打開了新的大門。

1.2 ASCII編碼

ASCII第一次以規範標準的類型發表是在1967年,當時僅有美國在使用計算機,於是,美國國家標準學會(American National Standard Institute , ANSI) 就蒐集了美國所有需要表示的字符,共,爲其建立了一張字符編碼表,從0-127每個數字映射了一個字符,如此一來,計算機就可以表示美國當時所有的字符了。而因爲僅有128個字符,只需要 7個bit即可表示,單計算機的最小儲存單位爲字節,因此,ASCII使用一個字節表示

  • 0000 0000 ~ 0010 0000 (0 ~ 32 )及127(共33個)是控制字符或通信專用字符(其餘爲可顯示字符),
  • 0011 0000 ~ 0011 1001 (48~57)爲0到9十個阿拉伯數字。
  • 0100 0001 ~ 0101 1010 (65 ~ 90)爲大寫的A-Z字母
  • 0110 0001 ~ 0111 1010 (97 ~ 122)爲小寫的a-z字母

參考自: 百度百科:ASCII

爲什麼大小寫字母之差剛好是32呢?

Ascii裏的大小寫代碼很簡單,只是使用位運算來處理英文字母的大小寫轉換,因爲大小寫相差剛剛32,unicode碼裏面有各種字符之間轉換的碼錶,而ascii轉換碼錶很簡單,+-32即可,所以使用0x5f和0x20來做位運算就可以進行轉換了,一個小的改進帶來的價值有多大。。如果你有幾百臺機器在做大小寫不敏感的字符串匹配和分析,這個改進的價值幾何呢?我不清楚,也許google能給個答案。
32,這個數字很湊巧,剛好可以使用位運算來對大小寫進行轉換,其實是在1963年一次投票後Ascii碼中大小寫才改進爲相差32:

參考自: ASCII碼的一段歷史

從ascii中,我們已經能隱隱感覺到字符編碼中常說的幾個術語:

  • 字符:現實世界中的一些符號,表示現實世界中的信息
  • 字符集:現實世界中字符的集合
  • 字符編碼:字符映射爲數字的映射規則,數字纔是最終用於計算機表示的對應字符的格式

1.3 EASCII編碼和ISO/IEC 8859編碼

計算機逐漸從美國發展到了歐洲,而歐洲國家除了ASCII中的字符外,還有許多其他字符需要表示,這時候ASCII的字符編碼已經滿足不了需求了,而ASCII編碼中僅使用了7個bit,最高位並沒有使用,也就意味着若使用上這個第8位,可以表示最多256個字符,於是歐洲國家分別對 ASCII中的 128-255編號進行編碼,這就衍生出了EASCII編碼

而歐洲各國都使用不同的字符編碼,通信起來就較爲麻煩,於是衍生出了ISO/IEC 8859-n 編碼(n是1-16,12未定義)依據不同的字符集將字符編碼分爲多個代碼頁,分別對應與 1-16,這樣,各個國家就可以依據需要使用不同的字符編碼

參考自: 刨根究底字符編碼之四——EASCII及ISO 8859字符編碼方案

1.4 GB2312編碼,GBK,GB18030, BIG5編碼

1.4.1 GB2312

中國漢字太複雜,太多了,當計算機傳入中國後,發現僅有一個字節完全不夠用,於是中國國家標準總局發佈了GB 2312(《信息交換用漢字編碼字符集·基本集》),並對該字符集進行了編碼,GB 2312 對任意一個字符都採用兩個字節表示

  • GB 2312 對任意一個圖形字符都採用兩個字節表示,並對所收漢字進行了“分區”處理,每區含有 94 個漢字/符號,分別對應第一字節和第二字節。這種表示方式也稱爲區位碼。
  • 01-09 區爲特殊符號。
  • 16-55 區爲一級漢字,按拼音排序。
  • 56-87 區爲二級漢字,按部首/筆畫排序。
  • 10-15 區及 88-94 區則未有編碼。
  • GB 2312 的編碼範圍爲 2121H-777EH,與 ASCII 有重疊,通行方法是將 GB 碼兩個字節的最高位置 1 以示區別。

1.4.2 GBK

有部分字符尚未收入GB2312中,而GBK就是GB2312的擴充,與GB2312向下兼容,同樣採用雙字節進行編碼

1.4.3 GB18030

最新一代中文編碼字符集,採用多字節變長編碼,每個字符由1、2、4個字節編碼

1.4.4 BIG5

BIG5是與GB2312同時期的編碼格式,GB2312字符集中並沒有收錄繁體字,而臺灣等地是使用繁體字的,因此BIG5應運而生,主要收錄了繁體字字符集,並進行編碼

參考自: GB2312、GBK、GB18030 這幾種字符集的主要區別是什麼?

BIG5詳細信息可以見 百度百科:大五碼

這裏,有幾個概念需要進行解釋:

  • 字符集:這個前面已經說過,是一個字符的集合,如這裏的GB2312和BIG5
  • 字符編碼:這個前面也說過,是字符映射爲數字的一個映射規則,可以理解爲一種標準,而這裏的GB2312和BIG5都給出了字符的映射規則,因此他們也是字符編碼
  • 編碼:字符映射爲數字的具體方式,可以理解爲標準的具體實現方式,ASCII很簡單,單字節轉爲2進制即可,而GB2312和BIG5則複雜一些,給出了每個字節詳細的映射規則,
  • 解碼:字符編碼後,需要依據對應的編碼規則對編碼後的字節進行解碼

1.5 Unicode,UTF16,UTF8

1.5.1 Unicode

計算機世界有了這麼多種字符編碼標準,而且他們之間大多互不兼容,這樣就導致當一個應用需要在多個國家發佈時,字符編碼成了難題,在本國編碼下運行正確的程序,到了其他國家可能就是亂碼,爲了解決這個難題,國際標準化組織(ISO)一些軟件製造商分別開始開發一個統一的字符編碼標準,後來,他們發現在做同樣的事情,並且也世界上不需要兩套不同標準的字符編碼,於是他們進行合併,共同開發了Unicode

Unicode characters — A Global Standard to Support ALL the World’s Languages

Unicode是一個用於支持全球語言的統一標準

  • Unicode致力於定製一個足夠大的編碼表,用以支持全世界的語言系統
  • Unicode爲每個字符提供了一個獨一無二的編碼(碼點,也就是一個數字)

Unicode歷史版本
在C++中,可以使用 \u\U開頭的16進制數字來表示Unicode中的字符,在任意支持Unicode的編譯器中,都可以在內部表示對應碼點的字符,而具體使用何種編碼格式,可以依據計算機使用的編碼系統變化
比如

 std::cout << "let them come to \u4E2D\u56FD.\n";

在這裏插入圖片描述
其中 4E2D和56FD分別是中、國的Unicode碼點,要查某個字符的編碼可以到這裏查詢: https://unicode-table.com/en/

《C++ Primer Plus 第6版》
碼點:字符編碼系統中字符的數字編號,
在Unicode中,Unicode碼點通常類似 U+4E2D, U表示這是一個Unicode字符,而4E2D是該字符的16進制編號

關於UnicodeUCS的區別,可以參考這篇文章:unicode和ucs的區別

1.5.2 UTF-16,UTF-8

現在我們知道,Unicode是一種編碼標準,它制訂了每個字符的碼點,但是問題來了,Unicode並沒有指定碼點如何具體編寫爲二進制,它不像ASCII和GBK等編碼標準,在指定字符碼點的同時也制訂了每個碼點編寫爲二進制的規則;

UTF-8和UTF-16就是常用的將Unicode的碼點編碼爲具體二進制的編碼規則,也就是我們常說的UTF-8編碼UTF-16編碼

關於UTF-8編碼規則,有許多講的很好的文章,這裏我就不多介紹了,有興趣可以看看一下幾篇文章:
阮一峯: 字符編碼筆記:ASCII,Unicode 和 UTF-8
知乎問題:Unicode 和 UTF-8 有什麼區別?
UTF-16就簡單了,簡單的講Unicode碼點使用兩個字節表示即可,
不過這裏面有大端序小端序的問題,後面進行詳談

二、一些常見概念說明

Unicode編碼:前面我們知道,Unicode是一個字符集,本身談不上編碼,一般情況下,未指明具體編碼爲UTF-8和UTF-16時,Unicode編碼指的是UTF-16
ANSI編碼ANSI本身並不是一種編碼格式,但是在記事本中,另存爲時,可以選擇保存爲ANSI格式在這裏插入圖片描述一般說ANSI編碼格式指的是當前系統環境的默認編碼格式,比如中國地區的windows系統(安裝系統時選擇的地區是中國,或者在控制面板->區域中進行設置)默認是GBK編碼

運行時編碼環境:指的是程序運行時使用那種編碼運行,一般取決於運行程序的系統使用的是哪種編碼,決定了程序最終展示出來的字符串的字符編碼,比如你的系統使用的是 ASCII,但是程序需要顯示中文字符,這時候顯示的就是亂碼了
編譯器字符編碼:告訴編譯器,程序使用的字符編碼是那種類型,比如UTF-16,那麼編譯器會使用UTF-16對程序中的字符進行編碼,Visual Studio中有兩種:Use Unicode Character Set,Use Multi-Byte Character Set分別指的是UTF-16UTF-8,具體可以查看這裏Unicode and Multibyte Character Set (MBCS) Support
代碼文本的編碼環境:這個很好理解,代碼本身是一個文本,這個文本的編碼,


以後想到了補充

參考文檔:
[1]字符編碼的前世今生
[2]百度百科:ASCII
[3]ASCII碼的一段歷史
[4] 刨根究底字符編碼之四——EASCII及ISO 8859字符編碼方案
[5] GB2312、GBK、GB18030 這幾種字符集的主要區別是什麼?
[6] 百度百科:大五碼
[7]Unicode characters — A Global Standard to Support ALL the World’s Languages
[8]unicode和ucs的區別
[9]阮一峯: 字符編碼筆記:ASCII,Unicode 和 UTF-8
[10]知乎問題:Unicode 和 UTF-8 有什麼區別?
[11]Unicode, UTF, ASCII, ANSI format differences

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