C語言中的字符串與字符集詳解


字符集理論及應用詳解

一、字符集和字符編碼

1、定義

字符集(Character Set/Charset)是一個系統支持的所有抽象字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。[1]簡單來說,字符集就是一個表。這個表有兩列,一列是各種字符,另一列是每個字符鎖對應的編號。注意,字符集只是一個規則,或者說是標准。它只定義每個字符對應的編碼,建立字符和數字的對應關系,而不存儲每個字符的圖像。存儲字符圖像的是字體文件。可以這樣理解:字體文件中存了很多張圖片,每一張圖片都是一個字符的樣子,同時每個圖片都有自己的名字(可能不止一個),這個名字就是圖片中的字符在字符集中的編碼。

圖片可以看作是字體文件中的一個字符,名字可以看作是其對應的編碼(這里是Unicode字符集指定的編碼)

字符編碼(Character Encoding)是一套法則,使用該法則能夠對自然語言的字符的一個集合(如字母表或音節表),與其他東西的一個集合(如號碼或電脈沖)進行配對。即在符號集合與數字系統之間建立對應關系,它是信息處理的一項基本技術。通常人們用符號集合(一般情況下就是文字)來表達信息。而以計算機為基礎的信息處理系統則是利用元件(硬件)不同狀態的組合來存儲和處理信息的。元件不同狀態的組合能代表數字系統的數字,因此字符編碼就是將符號轉換為計算機可以接受的數字系統的數,稱為數字代碼。[1]簡單來說,字符編碼就是表示字符的方法。例如,如何將字符集中字符自己的編號存在計算機中。

2、常見字符集

常見字符集有兩大類,分別是ANSI和Unicode。其中ANSI又包含了很多具體的字符集,例如GB2312,BIG5,Shift-JIS等。

ANSI字符集:

ANSI編碼包含了一系列字符集,所以准確來講,它並不能被叫做一個字符集。但是由於技術原因(下面會講),這一系列字符集同時只能使用一個,所以把整個ANSI編碼稱作ANSI字符集來討論也沒有什么大問題。ANSI字符集比Unicode字符集出現的早,它出現的目的是去解決當時ASCII編碼不夠用的情況。ASCII是美國當時造出來編碼英文字符的一套系統,也可以算是一種字符集。最先它使用[0,0x7f]范圍內的數字來編碼英文字母,標點符號以及控制字符(例如空格,換行等)。后來又添加了一些拉丁字母和亂七八糟的東西,又使用了[0x80,0xff]范圍內的數字來編碼。這部分被叫做ASCII擴展表。總而言之,ASCII字符集使用[0,0xff]區間內的數字為字符編碼,存儲起來也只需要一個字節。

ASCII基本表

ASCII擴展表

然而,ASCII字符集仍然不能包含漢字字符。這事因為漢字真的太多了,[0,0xff]這個區間內只有255個數字,對漢字來說根本不夠用。為了解決這個問題,ANSI編碼出現了。ANSI規定使用兩個字節來為一個字符編碼,這樣就包含了[0,0xffff]區間內的數字,一共可以為65536個字符編碼。為了兼容之前的ASCII字符集,ANSI編碼還規定,[0,0x7f]這個范圍內的編碼必須和ASCII字符集一樣。
65536個字符雖多,但是仍然是不足以涵蓋世界上所有字符的。因此,每類文字有各自不同的字符集標准,叫做代碼頁(Code Page)。每個代碼頁有不同的編碼規則,因此同一個字碼(數字)在不同代碼頁中對應不同的字符。這樣的后果就是,在顯示一段文字之前,必須先指定其代碼頁,而且同一次顯示的文字只能使用同一個代碼頁。(如何切換代碼頁)

常見的代碼頁有:GB2312(簡體中文),BIG5(繁體中文),Shift-JIS(日文)等。

代碼頁例子

Unicode字符集:

Unicode字符集晚於ANSI字符集出現,而它的出現徹徹底底地解決了為世界上所有文字編碼的問題。Unicode字符集規定使用4個字節來為一個字符編碼,理論上編碼范圍為[0,0xffffffff],也就是4294967296個字符(42億)。事實上Unicode字符集並不能夠包含這么多字符,也沒必要。Unicode字符集只使用了[0,0x10ffff]區間內的數字為字符編碼,而且還包含一些保留區間,例如[0xd800,0xdfff]區間就是為了兼容UTF-16編碼格式的保留區間。它將每65536個字符編為一個平面:其中[0,0xffff]被稱為基本平面,包含所有語言常用字符;[0x010000,0x10ffff]被稱為擴展平面,包含其他所有的不常用字符、其他符號以及生僻語言(例如表情、小圖標、楔形文字等)。

3、Unicode字符集的常見編碼格式

UTF-8:

一個字符的UTF-8編碼長度為1-4字節,具體長度由該字符的Unicode碼確定。(編碼規則見下表)

Unicode碼范圍 Unicode碼(二進制) UTF-8編碼 UTF-8編碼長度(字節)
[0,0x7f] 高位00000000 00000000 0aaaaaaa低位 首字節0aaaaaaa 1
[0x80,0x07ff] 高位00000000 00000bbb bbaaaaaa低位 首字節110bbbbb 10aaaaaa尾字節 2
[0x0800,0xffff] 高位00000000 ccccbbbb bbaaaaaa低位 首字節1110cccc 10bbbbbb 10aaaaaa尾字節 3
[0x010000,0x10ffff] 高位000dddcc ccccbbbb bbaaaaaa低位 首字節11110ddd 10cccccc 10bbbbbb 10aaaaaa尾字節 4

舉例:如何得出字符'𣱕'的UTF-8編碼格式的Unicode碼

'𣱕'字的資料,摘自Unicode標准文檔[2]
(提示:三個字符分別為三個字型, 其字碼都是相同的)

1:0x23C55在0x10000與0x10FFFF之間,它的結構應該符合上表中的第四行所描述的結構。

2:將0x23C55轉為二進制,應為:

高位00000010 00111100 01010101低位

3:按照規則,進行轉換:

高位00000010 00111100 01010101低位
↓ ↓ ↓
首字節11110000 10100011 10110001 10010101尾字節

得出,字符'𣱕'的UTF-8編碼格式的Unicode碼為:首字節0xf0 0xa3 0xb1 0x95尾字節

UTF-16:

一個字符的UTF-16編碼長度為2字節或者4字節,具體長度由該字符的Unicode碼確定。(編碼規則見下表)

Unicode碼范圍 Unicode碼 UTF-16編碼 UTF-16編碼長度(字節)
[0,0xffff] X 首字X的低16位(其實就是一模一樣) 2
[0x010000,0x100000] X 首字((X-0x010000)的[10,19]位)+0xd800 ((X-0x010000)的[0,9]位)+0xdc00尾字 4

舉例:如何得出字符'𣱕'的UTF-16編碼格式的Unicode碼

1:0x23C55在0x10000與0x10ffff之間,它的結構應該符合上表中的第四行所描述的結構。

2:將0x23c55減去0x10000, 得到0x13c55;

3:將0x13c55轉為2進制:

高位00000001 00111100 01010101低位

4:按照規則,進行轉換:

高位00000001 00111100 01010101低位
   [10,19]位    [0,9]位
    +0xd800     +0xdc00
↓ ↓ ↓
首字1101100001001111 1101110001010101尾字

得出,字符'𣱕'的UTF-16編碼格式的Unicode碼為:首字0xd84f 0xdc55尾字

存儲方式分兩種,分別是大端和小端

小端:首字節0x4f 0xd8 0x55 0xdc尾字節
大端:首字節0xd8 0x4f 0xdc 0x55尾字節

UTF-32:

一個字符的UTF-16編碼長度為4個字節,值與其Unicode碼一模一樣,只是存儲分小端和大端而已。(不常用)

UCS-2

一個字符的UCS-2編碼長度為2個字節,只能編碼[0,0xffff]范圍內的Unicode基本平面字符。值和Unicode碼一樣,分大小端。

UCS-4

同UTF-32。

二、程序實現

1、互相轉換

引用

1. "字符集和字符編碼(Charset & Encoding)" RUNOOB.COM https://www.runoob.com/w3cnote/charset-encoding.html (accessed Jun. 30, 2021)

2. The Unicode Standard, Version 13.0, 2020. [Online]. Available: https://www.unicode.org/Public/13.0.0/charts/CodeCharts.pdf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM