字符編碼詳解

本文主要介紹了字符編碼的基礎知識,以及常見的字符編碼類型,比如ASCII,Unicode,UTF-8,ISO 8859等,以及各種編碼之間的關係,同時專門解釋了中文字符相關的編碼標準,包括GB2312,GBK,GB18030,也專門解釋了Windows系統中的Code Page,以及相關的BOM等內容

縮略詞

ASCII (ASCII)

American Standard Code for Information Interchange

美國信息交換標準代碼

BMP (BMP)

Basic Multilingual Plane

基本多文種平面

EBCDIC (EBCDIC)

Extended Binary Coded Decimal Interchange Code

擴展二進制編碼十進制交換碼

IANA (IANA)

Internet Assigned Numbers Authority

互聯網號碼分配局

ISO/IEC (ISO/IEC)

International Organization for Standardization / International Electrotechnical Commission

國際標準化組織和國際電工委員會

UCS (UCS)

Universal Character Set

通用字符集

UTF (UTF)

Unicode Transformation Format

Unicode轉換格式

正文之前

1. 目的

本文旨在講清楚字符編碼的概念和來龍去脈,和常見標準之間的關係和區別。

2. 本文內容

個人對於字符編碼的理解,最開始主要是看了阮一峯的這篇文章:

【轉】字符編碼筆記:ASCII,Unicode和UTF-8

然後自己花了更多的時間,蒐集整理了和字符編碼的更詳細的知識,整理出來,以供大家參考。

其中也摘錄了該貼的部分內容。

3. 聲明

任何問題,意見,建議等,都歡迎一起探討:admin (at) crifan.com。

第 1 章 字符編碼相關的背景知識

1.1. 拉丁字母

1.1.1. 我們的目標

在介紹計算機的字符編碼知識前,先來說說這個拉丁字母,估計也會有人和我一樣,對於拉丁字母和英文字母以及漢語拼音中的字母的關係,不是很清楚。

拉丁字母,也叫羅馬字母,是當今世界上使用最廣的字母系統。

拉丁字母,或者說基本的拉丁字母,就是你所常見的到的ABCD等26個英文字母。

原先是歐洲那邊使用的,後來由於歐洲殖民主義,導致後來的美洲等地,也是用的這套字母體系。

而其他有些地方,比如越南等,本來有自己的文字語言的,結果受西方文化的影響和由於基督教的傳播,也用拉丁字母了。

所以總的說,現在歐洲多數國家,美洲,澳洲,非洲的多數國家,都是用的拉丁字母,即你所常見的英文字母,也是拉丁字母。而中國的漢語拼音,也是用的這個拉丁字母。

其中,歐洲很多國家,是對已有的26個基本的拉丁字母,加上連字,變音字符,弄出個衍生拉丁字母,但是還是屬於拉丁字母。

說了這麼多,就是要讓你知道,後面內容所提到的英文字母,其來源於拉丁字母,而且我們漢語的漢語拼音,也是拉丁字母。

即:

  • 基本的拉丁字母 = 26個英文字母 = 漢語中的漢語拼音
  • 衍生的拉丁字母 = 從基本的26個英文字母,加上連字,變音等字符而衍生出來的拉丁字母 = 很多西歐國家的字母 (每個國家都不太一樣)

1.2. 什麼是字符編碼

計算機中存放的都是0和1的二進制值。8個位對應一個字節,常用16進制來表示。

而我們普通用戶所希望看到的是,計算機把其所存儲的對應的16進制的數值,轉化爲對應的字符,包括英文和中文等其他語言的字符,然後輸出到屏幕上。

而所謂編碼,就是,定義了一套規則,去指定,哪些數值,對應着哪些字符。

舉個最簡單的例子,常見65=0x41對應的是大寫字母A,97=0x61對應的是小寫字母a,而這套數值和字母之間的映射關係,說白了,就是一套規則,就叫做字符編碼,即我們常說的ASCII編碼。

那有人會問了,如果我定義了一套規則,假如叫張三編碼,然後故意去把ASCII中的映射關係改變,比如97=0x61對應的是大寫字母A,65=0x41對應的是小寫字母a,等等,可不可以?答案是,完全可以,不過這套規則,首先沒有得到所有計算機業界的一致認同,所以,除了你自己用,其他人不原意使用,那麼也就是沒了存在的價值了。

換句話說,當初ASCII之所以這麼定義這套規則,就是這麼定義了而已,然後大家都接受這個標準,然後就都用這個定義了。

即,如果當初定義爲0x41代表的是小寫字母a,而不是大寫字母A,那麼現在你所看到的,就是小寫字母a就是對應着計算機中存儲的0x41,而不是之前的0x61了。

所以,簡單的說就是:

所謂字符編碼,就是定義了一套規則,指定了計算機中存放的這麼多值中的哪個值,對應了電腦屏幕顯示出來的哪個字母。

第 2 章 字符編碼標準

 

2.1. 只支持基本的拉丁字符的字符編碼:ASCII

2.1.1. ASCII的由來

計算機剛出現的時候,雖然是美國人發明的,但是也要面對一個問題,即如何將對應的計算機中的數值,轉化爲對應的字母,而顯示出來,即採用什麼樣的規則,而當時,各個廠家或公司都有自己的做法,也就是說,編碼規則沒有統一。

但是相對來說,得到大家認可的有,IBM的EBCDIC和此處要談的ASCII。

其中EBCDIC現在基本沒人再用,而大家統一都用ASCII了。

ASCII,即American Standard Code for Information Interchange,美國信息交換標準代碼。

單獨看名字,就是知道,這字符編碼是設計給美國人用的。

那是因爲,計算機是美國人所發明和使用的,所以計算機的早期,所設計編碼標準,自然需要先爲英文字符來設計和考慮,所以此最早的字符編碼ASCII可以顯示常見的英文字符,也可以這麼說,也只能顯示基本的英文字符。

由於ASCII編碼中,不包括其他歐洲的很多國家的衍生的拉丁字母的那些字符,更不包含亞洲,比如中國的中文字符,因此纔會有後面所提到的各種其他字符集,爲的就是可以讓計算機顯示出自己國家的字符。

2.1.2. ASCII編碼規則

ASCII的編碼規則,由於最初只是爲英文字母所考慮的,而英文只有26個字母,以及加上其他大小寫字母,常見的字符,常見數字等,所有的加起來,也就幾十個,而一個字節8位中前7位的理論上可以表示27=128個字符,所以對於設計出來的編碼規則來說,只需要用一個字節來表示,就足夠了。

即ASCII編碼規則中規定,用單個字節共8位來表示字符,其中最高位爲0,其他7位所對於的每一個值,映射到某個特定的字符,這樣就形成了ASCII編碼。

ASCII共包含了27=128個字符。

其中包括33個不可顯示的字符和95個可顯示的字符。

而對於ASCII編碼規則,簡單說就是:

7位的字符編碼,即每個字節的最高位第8位爲0,其餘7位的某個值對應着某個字符。

ASCII字符集共27=128個字符 = 33個控制字符 + 95個可見字符。

  >ASCII中的可顯示的字符和不可顯示字符

ASCII中可顯示的字符,也叫可打印printable字符;

而ASCII中的值爲0 – 31的那些字符,叫做不可顯示的字符,也叫不可見字符,不可打印(non-printable)字符,由於其字符的作用是起一定的控制作用,所以常稱爲控制字符(control character),即不同的字符實現不同的功能,因此又稱爲功能字符(function code,function character)。

即ASCII字符集中:

不可見字符

=不可打印(non-printable)字符

=控制字符(control character)

=功能字符(function code,function character)

對於ASCII中的控制字符,都包括哪些,以及每個字符的詳細含義,第 2.1.2.1 節 “ASCII字符集中的功能/控制字符”中會有詳細介紹。

2.1.2.1. ASCII字符集中的功能/控制字符

2.1.2.1.1. 什麼是Function Code功能碼或 Function Character功能字符

ASCII字符集,大家都知道吧,最基本的包含了128個字符。其中前32個,0-31,即0x00-0x1F,都是不可見字符。這些字符,就叫做控制字符。

這些字符沒法打印出來,但是每個字符,都對應着一個特殊的控制功能的字符,簡稱功能字符或功能碼Function Code。

簡言之:ASCII中前32個字符,統稱爲Function Code功能字符。

此外,由於ASCII中的127對應的是Delete,也是不可見的,所以,此處根據筆者的理解,也可以歸爲Function Code。

此類字符,對應不同的“功能”,起到一定的“控制作用”,所以,稱爲控制字符。

關於每個控制字符的控制功能縮寫,參見表 2.1 “ASCII中的控制字符”

表 2.1. ASCII中的控制字符

十進制 十六進制 控制字符 轉義字符 說明 Ctrl + 下列字母
0 00 NUL \0 Null character(空字符) @
1 01 SOH   Start of Header(標題開始) A
2 02 STX   Start of Text(正文開始) B
3 03 ETX   End of Text(正文結束) C
4 04 EOT   End of Transmission(傳輸結束) D
5 05 ENQ   Enquiry(請求) E
6 06 ACK   Acknowledgment(收到通知/響應) F
7 07 BEL \a Bell(響鈴) G
8 08 BS \b Backspace(退格) H
9 09 HT \t Horizontal Tab(水平製表符) I
10 0A LF \n Line feed(換行鍵) J
11 0B VT \v Vertical Tab(垂直製表符) K
12 0C FF \f Form feed(換頁鍵) L
13 0D CR \r Carriage return(回車鍵) M
14 0E SO   Shift Out(不用切換) N
15 0F SI   Shift In(啓用切換) O
16 10 DLE   Data Link Escape(數據鏈路轉義) P
17 11 DC1   Device Control 1(設備控制1) /XON(Transmit On) Q
18 12 DC2   Device Control 2(設備控制2) R
19 13 DC3   Device Control 3(設備控制3) /XOFF(Transmit Off) S
20 14 DC4   Device Control 4(設備控制4) T
21 15 NAK   Negative Acknowledgement(拒絕接收/無響應) U
22 16 SYN   Synchronous Idle(同步空閒) V
23 17 ETB   End of Trans the Block(傳輸塊結束) W
24 18 CAN   Cancel(取消) X
25 19 EM   End of Medium(已到介質末端/介質存儲已滿) Y
26 1A SUB   Substitute(替補/替換) Z
27 1B ESC \e Escape(溢出/逃離/取消) [
28 1C FS   File Separator(文件分割符) \
29 1D GS   Group Separator(分組符) ]
30 1E RS   Record Separator(記錄分隔符) ^
31 1F US   Unit Separator(單元分隔符) _
32 20 SP   White space [Space]
127 7F DEL   Delete(刪除) ?


即在C語言中或其他地方如何表示。


可以通過 “Ctrl+對應字母/按鍵”實現上述控制字符的輸入

下面列舉一些你可能遇到的情況:


注意此處想要在鍵盤上輸入這三個字符的話,是需要通過Shift加上對應字符才能輸入的:

  • @:用Shift + 2輸入
  • ^:用Shift + 6輸入
  • _:用Shift + -輸入

32=0x20,對應的是空格(Blank Space)鍵。不需要加Ctrl鍵,即可直接通過鍵盤上的空格鍵輸入。


127=0x7F=刪除(Delete)鍵;,除了可以用鍵盤上的刪除鍵輸入,也可以用'Ctrl+?'輸入。

2.1.2.1.2. ASCII中的Function/Control Code功能字符的詳細含義
2.1.2.1.2.1. 0 – NUL – NULl 字符/空字符

ASCII字符集中的空字符,NULL,起初本意可以看作爲NOP(中文意爲空操作,就是啥都不做的意思),此位置可以忽略一個字符。

之所以有這個空字符,主要是用於計算機早期的記錄信息的紙帶,此處留個NUL字符,意思是先佔這個位置,以待後用,比如你哪天想起來了,在這個位置在放一個別的啥字符之類的。

後來呢,NUL字符被用於C語言中,字符串的終結符,當一個字符串中間出現NUL / NULL,代碼裏面表現爲\0,的時候,就意味着這個是一個字符串的結尾了。這樣就方便按照自己需求去定義字符串,多長都行,當然只要你內存放得下,然後最後加一個\0, 即空字符,意思是當前字符串到此結束。

2.1.2.1.2.2. 1 – SOH – Start Of Heading 標題開始

如果信息溝通交流主要以命令和消息的形式的話,SOH就可以用於標記每個消息的開始。

1963年,最開始ASCII標準中,把此字符定義爲Start of Message,後來又改爲現在的Start Of Heading。

現在,這個SOH常見於主從(master-slave)模式的RS232的通信中,一個主設備,以SOH開頭,和從設備進行通信。這樣方便從設備在數據傳輸出現錯誤的時候,在下一次通信之前,去實現重新同步(resynchronize)。如果沒有一個清晰的類似於SOH這樣的標記,去標記每個命令的起始或開頭的話,那麼重新同步,就很難實現了。

 

 

 

2.1.2.1.2.3. 2 – STX,3 – ETX

2 – STX – Start Of Text 文本開始

3 – ETX – End Of Text 文本結束

通過某種通訊協議去傳輸的一個數據(包),稱爲一幀的話,常會包含一個幀頭,包含了尋址信息,即你是要發給誰,要發送到目的地是哪裏,其後跟着真正要發送的數據內容。

而STX,就用於標記這個數據內容的開始。接下來是要傳輸的數據,最後是ETX,表明數據的結束。

其中,中間具體傳輸的數據內容,ASCII規範並沒有去定義,其和你所用的傳輸協議,具體自己要傳什麼數據有關。

幀頭 數據或文本內容
SOH(表明幀頭開始) ......(幀頭信息,比如包含了目的地址,表明你發送給誰等等) STX(表明數據開始) ......(真正要傳輸的數據) ETX(表明數據結束

不過其中有趣的是,1963年,ASCII標準最初版本的時候,把現在的STX叫做EOA(End Of Address),ETX叫做(End Of Message)。

這是因爲,最早的時候,一個消息中,總是包含一個開始符和一個終止符。現在的新的定義,使得可以去發送一個固定長度的命令,而只用一個SOH表明幀頭開始即可,而不需要再加上一個命令終止符或幀頭結束符。

總結一下:

一般發送一個消息,包含了一個幀頭和後面真正要傳的數據。

而對於幀頭,屬於控制類的信息,這部分之前屬於命令,後面的真實要傳的數據屬於數據。即消息=幀頭+數據。

而之前的命令都要有個開始符和結束符,這樣就是:

消息

= 幀頭 + 要傳的數據

= 幀頭開始+幀頭信息+幀頭結束 + 要傳的數據

而現在新的定義,使得只需要:

消息

= 幀頭 +要傳的數據

= SOH(表明幀頭開始)+幀頭信息+ 要傳的數據

= SOH(表明幀頭開始)+幀頭信息 + STX + 數據內容+ETX

就可以少用一個幀頭結束符。

而如今,在很多協議中,也常見到,一個固定長度的幀頭,後面緊接着就是數據了,而沒有所謂的幀頭結束符之類的東西去區分幀頭和數據。

2.1.2.1.2.4. 4 – EOT – End Of Transmission 傳輸結束
2.1.2.1.2.5. 5 – ENQ – ENQuiry 請求
2.1.2.1.2.6. 6 – ACK – ACKnowledgment 迴應/響應
2.1.2.1.2.7. 7 – BEL – [audible] BELl

在ASCII字符集中,BEL,是個比較有意思的東東。

因爲其原先本意不是用來數據編碼的,於此相反,ASCII中的其他字符,都是用於字符編碼(即用什麼字符,代表什麼含義)或者起到控制設備的作用。

BEL用一個可以聽得見的聲音,來吸引人們的注意,其原打算即用於計算機也用於一些設備,比如打印機等。

C語言裏面也支持此BEL,用a來實現這個響鈴。

2.1.2.1.2.8. 8 – BS – BackSpace 退格鍵

退格鍵的功能,隨着時間變化,意義也變得不同了。

起初,意思是,在打印機和電傳打字機上,往回移動一格光標,以起到強調該字符的作用。

比如你想要打印一個a,然後加上退格鍵後,就成了aBS^。在機械類打字機上,此方法能夠起到實際的強調字符的作用,但是對於後來的CTR下時期來說,就無法起到對應效果了。

而現代所用的退格鍵,不僅僅表示光標往回移動了一格,同時也刪除了移動後該位置的字符。在C語言中,退格鍵可以用b表示。

2.1.2.1.2.9. 9 – HT – Horizontal Tab 水平製表符

ASCII中的HT控制符的作用是用於佈局的。

其控制輸出設備前進到下一個表格去處理。

而製表符Table/Tab的寬度也是靈活不固定的,只不過,多數設備上,製表符Tab的寬度都預定義爲8。

水平製表符HT不僅能減少數據輸入者的工作量,對於格式化好的文字來說,還能夠減少存儲空間,因爲一個Tab鍵,就代替了8個空格,所以說省空間。

對於省空間的優點,我們現在來看,可能會覺得可笑,因爲現在存儲空間已足夠大,一般來說根本不會需要去省那麼點可憐的存儲空間。

但是,實際上在計算機剛發明的時候,存儲空間(主要指的是內存)極其有限也極其昂貴,而且像ZIP等壓縮方法也還沒發明呢,所以對於當時來說,對於存儲空間,那是能夠省一點是一點,省任何一點,都是好的,也都是不容易的,省空間就是省錢啊。

C語言中,用t表示製表符。

2.1.2.1.2.10. 10 – LF – Line Feed 換行

LF,直譯爲(給打印機等)喂一行,意思就是所說的,換行。

換行字符,是ASCII字符集中,被誤用的字符中的其中一個。

LF的最原始的含義是,移動打印機的頭到下一行。而另外一個ASCII字符,CR(Carriage Return)纔是將打印機的頭,移到最左邊即一行的開始,行首。很多串口協議和MS-DOS及Windows操作系統,也都是這麼實現的。

而於此不同,對於C語言和Unix操作系統,其重新定義了LF字符的含義爲新行,即LF和CR的組合才能表達出的,回車且換行的意思。

雖然你可以爭論哪種用法是錯的,但是,不可否認,是從程序的角度出發,C語言和Unix對此LF的含義實現顯得就很自然,而MS-DOS的實現更接近於LF的本意。

如果最開始ASCII標準中,及定義 CF也定義newline,那樣意思會清楚,會更好理理解:

LF表示物理上的,設備控制方面的移動到下一行(並沒有移動到行首);

新行(newline)表示邏輯上文本分隔符,即回車換行。

不過呢,現在人們常將LF用做newline新行的功能,而大多數文本編輯軟件也都可以處理單個LF或者CR/LF的組合了。

LF在C語言中,用n表示。

2.1.2.1.2.11. 11 – VT – Vertical Tab 垂直製表符

垂直製表符,類似於水平製表符Tab,目的是爲了減少佈局中的工作,同時也減少了格式化字符時所需要存儲字符的空間。VT控制碼用於跳到下一個標記行。

說實話,還真沒看到有些地方需要用這個VT呢,因爲一般在換行的時候,都是用LF代替VT了。

2.1.2.1.2.12. 12 – FF – Form Feed 換頁

設計換頁鍵,是用來控制打印機行爲的。

當打印機收到此鍵碼的時候,打印機移動到下一頁。

不同的設備的終端對此控制碼所表現的行爲各不同。有些會去清除屏幕,而其他有的只是顯示^L字符或者是隻是新換一行而已。

Shell腳本程序Bash和Tcsh的實現方式是,把FF看作是一個清除屏幕的命令。C語言程序中用f表示FF(換頁)。

2.1.2.1.2.13. 13 – CR – Carriage return 機器的滑動部分/底座 返回 -> 回車

CR回車的原意是讓打印頭回到左邊界,並沒有移動到下一行。

隨着時間流逝,後來人把CR的意思弄成了Enter鍵,用於示意輸入完畢。

在數據以屏幕顯示的情況下,人們在Enter的同時,也希望把光標移動到下一行。

因此C語言和Unix操作系統,重新定義了LF的意思,使其表示爲移動到下一行。當輸入CR去存儲數據的時候,軟件也常常隱式地將其轉換爲LF。

2.1.2.1.2.14. 14 – SO,15 – SI

14 – SO – Shift Out 不用切換

15 – SI – Shift In 啓用切換

早在1960s年代,定義ASCII字符集的人,就已經懂得了,設計字符集不單單可以用於英文字符集,也要能應用於外文字符集,是很重要的。

定義Shift In 和Shift Out的含義,即考慮到了此點。

最開始,其意爲在西里爾語和拉丁語之間切換。

西里爾ASCII定義中,KOI-7用到了Shift字符。拉丁語用Shift去改變打印機的字體。

在此種用途中,SO用於產生雙倍寬度的字符,而用SI打印壓縮的字體。

2.1.2.1.2.15. 16 – DLE – Data Link Escape 數據鏈路轉義

有時候,我們需要在正在進行的通信過程中去發送一些控制字符。但是,總有一些情況下,這些控制字符卻被看成了普通的數據流,而沒有起到對應的控制效果。而ASCII標準中,定義DLE來解決這類問題。

如果數據流中檢測到了DLE,數據接收端則對其後面接下來的數據流中的字符,另作處理。

而關於具體如何處理這些字符,ASCII規範中則沒有具體定義,而只是弄了個DLE去打斷正常數據的處理,告訴接下來的數據,要特殊對待。

根據Modem中的Hayes通信協議DLE定義爲“無聲+++無聲”。

以我的觀點,這樣可能會更好:如果Hayes協議沒有把DLE處理爲嵌入通訊的無聲狀態,那樣就符合現存的標準了。

然而Hayes的開發者卻覺得+++用的頻率要遠高於原始的DLE,所以才這麼定義了。

2.1.2.1.2.16. 17 – DC1 – Device Control 1 / XON – Transmission on

這個ASCII控制字符儘管原先定義爲DC1, 但是現在常表示爲XON,用於串行通信中的軟件流控制。

其主要作用爲,在通信被控制碼XOFF中斷之後,重新開始信息傳輸。

用過串行終端的人應該還記得,當有時候數據出錯了,按Ctrl+Q(等價於XON)有時候可以起到重新傳輸的效果。

這是因爲,此Ctrl+Q鍵盤序列實際上就是產生XON控制碼,其可以將那些由於終端或者主機方面,由於偶爾出現的錯誤的XOFF控制碼而中斷的通信解鎖,使其正常通信。

2.1.2.1.2.17. 18 – DC2 – Device Control 2
2.1.2.1.2.18. 19 – DC3 – Device Control 3 / XOFF – Transmission off 傳輸中斷
2.1.2.1.2.19. 20 – DC4 – Device Control 4
2.1.2.1.2.20. 21 – NAK – Negative AcKnowledgment 負面響應-> 無響應, 非正常響應
2.1.2.1.2.21. 22 – SYN – SYNchronous idle
2.1.2.1.2.22. 23 – ETB – End of Transmission Block 塊傳輸中止
2.1.2.1.2.23. 24 – CAN – CANcel 取消
2.1.2.1.2.24. 25 – EM – End of Medium 已到介質末端,介質存儲已滿

EM用於,當數據存儲到達串行存儲介質末尾的時候,就像磁帶或磁頭滾動到介質末尾一樣。其用於表述數據的邏輯終點,即不必非要是物理上的達到數據載體的末尾。

2.1.2.1.2.25. 26 – SUB – SUBstitute character替補/替換
2.1.2.1.2.26. 27 – ESC – ESCape 逃離/取消

字符Escape,是ASCII標準的首創的,由Bob Bemer提議的。用於開始一段控制碼的擴展字符。如此,即可以不必將所有可能想得到的字符都放到ASCII標準中了。

因爲,新的技術可能需要新的控制命令,而ESC可以用作這些字符命令的起始標誌。

ESC廣泛用於打印機和終端,去控制設備設置,比如字體,字符位置和顏色等等。

如果最開始的ASCII標準中,沒有定義ESC,估計ASCII標準早就被其他標準所替代了,因爲其沒有包含這些新出現的字符,所以肯定會有其他新的標準出現,用於表示這些字符的。

即,ESC給開發者提供了,可以根據需要而定義新含義的字符的可能。

2.1.2.1.2.27. 28 – FS – File Separator 文件分隔符

文件分隔符是個很有意思的控制字符,因爲其可以讓我們看到1960s年代的時候,計算機技術是如何組織的。

我們現在,習慣於隨即訪問一些存儲介質,比如RAM,磁盤,但是在定義ASCII標準的那個年代,大部分數據還是順序的,串行的,而不是隨機訪問的。此處所說的串行的,不僅僅指的是串行通信,還指的是順序存儲介質,比如穿孔卡片,紙帶,磁帶等。

在串行通信的時代,設計這麼一個用於表示文件分隔符的控制字符,用於分割兩個單獨的文件,是一件很明智的事情。而FS的原因就在於此。

2.1.2.1.2.28. 29 – GS – Group Separator分組符

ASCII定義控制字符的原因中,其中一條就是考慮到了數據存儲方面的情況。

大部分情況下,數據庫的建立,都和表有關,包含了對應的記錄。同一個表中的所有的記錄,屬於同一類型。不同的表中的記錄,屬於對應的不同的類型。

而分組符GS就是用來分隔串行數據存儲系統中的不同的組。值得注意的是,當時還沒有使用word的表格,當時ASCII時代的人,把他叫做組。

2.1.2.1.2.29. 30 – RS – Record Separator記錄分隔符

記錄分隔符RS用於分隔在一個組或表內的多個記錄。

2.1.2.1.2.30. 31 – US – Unit Separator 單元分隔符

在ASCII定義中,在數據庫中所存儲的,最小的數據項,叫做Unit單元。而現在我們稱其field域。單元分隔符US用於分割串行數據存儲環境下的不同的域。

現在大部分的數據庫實現,要求大部分類型都擁有固定的長度。

儘管大部分時候可能用不到,但是對於每一個域,卻都要分配足夠大的空間,用於存放最大可能的成員變量。

這樣的做法,佔用了大量的存儲空間,而US控制碼允許域具有可變的長度。在1960s年代,數據存儲空間很有限,用US這個單元分隔符,將不同單元分隔開,這樣就可以實現更高效地存儲那些寶貴的數據。

另一方面,串行存儲的存儲效率,遠低於RAM和磁盤中所實現的表格存儲。我個人無法想象,如果現在的數據,還是存儲在自帶或者帶滾輪的磁帶上,會是何種景象。

2.1.2.1.2.31. 32 – SP – White SPace 空格鍵

也許你會爭論說,空格鍵是否真的能算是一個控制字符?因爲現在在普通文字中使用空格鍵是如此常見。

但是,既然水平製表符和退格鍵在ASCII中,都被叫做控制字符了,那麼我覺得也很自然地,可以把空格鍵(向前的空格)也叫做控制字符,畢竟,其本身並不代表一個真正的可見的字符,而僅僅只是很常用於輸出設備,用於處理位置前向移動一格,清除當前位置的內容而已。

在很多程序中,比如字符處理程序,白空格同樣可能從導致行尾轉到下一行行首,而網絡瀏覽器將多個空格組合成單個空格輸出。

所以,這更加堅定了我的想法,覺得完全可以把空格看成是一個控制字符,而不僅僅是一個很獨特的普通字符。

2.1.2.1.2.32. 127 – DEL – DELete 刪除

有人也許會問,爲何ASCII字符集中的控制字符的值都是很小的,即0-32,而DEL控制字符的值卻很大,是127。

這是由於這個特殊的字符是爲紙帶而定義的。而在那個時候,絕大多數的紙帶,都是用7個孔洞去編碼數據的。

而127這個值所對應的二進制值爲111 1111b,表示所有7個比特位都是高,所以,將DEL用在現存的紙帶上時,所有的洞就都被穿孔了,就把已經存在的數據都擦出掉了,就起到了對應的刪除的作用了。

2.1.2.1.3. 各種字符的標準的讀法/叫法

常見ASCII字符,以及其他非常見的字符,Unicode中的字符,其他特殊字符等等,這些字符的英文叫法,可以去Unicode官方找到:

http://www.unicode.org/charts/#symbols

比如:

ASCII字符/字母的叫法/讀法 如何讀 :

2.1.3. ISO 646

ASCII的字符編碼是美國自己定義的標準,而其對應的國際標準叫做ISO/IEC 646。

ISO/IEC是參考了多個國家的字符編碼標準,其中主要是美國ASCII標準,然後制定出來的7位的國際字符編碼標準。

所以,此處,可以簡單看成美國的國家標準ASCII和國際標準ISO/IEC 646,兩者是是等價的,即:

美國的國家的字符編碼標準ASCII

=國際的字符編碼標準ISO/IEC 646

2.2. 支持多種衍生拉丁字母的字符編碼:EASCII和ISO 8859

計算機出現之後,從美國發展到歐洲,而由於歐洲很多國家中所用到的字符中,除了基本的美國也用的那些拉丁字母之外,還有很多衍生的拉丁字母,而且是不同的國家用到的衍生字符都不太相同,所以歐洲人也遇到類似的問題,即如何將自己國家的那些字符,在計算機上顯示出來,這就需要設計一個合理的字符編碼,把所有這些字符都囊括其中。

即設計一個新編碼標準,即兼容舊的ASCII的編碼,又支持歐洲多個國家的那些衍生拉丁字母。

這樣的標準有兩個,一個是EASCII編碼標準,一個是國際標準ISO 8859字符編碼標準。

2.2.1. EASCII

將ASCII中的第八位也用上,那麼就是8位的字符編碼了,然後將EASCII中0xA0-0xFF這部分比ASCII碼擴充出來的編碼,用來表示表格符號、計算符號、希臘字母和特殊的拉丁符號等,這樣就可以實現支持那麼多歐洲的衍生拉丁字母了,也就是這個EASCII字符編碼了。但是EASCII雖然解決了這些西歐語言的字符顯示問題,但是對於其他語言顯示,比如中文等,還是無法處理顯示。

目前,很少使用EASCII,常用的是下面要介紹的第 2.2.2 節 “ISO 8859”編碼標準。

2.2.2. ISO 8859

2.2.2.1. ISO/IEC 8859出現的背景

前面已經提到了,正是因爲ASCII等字符編碼中,沒有包括歐洲很多國家所用到的一些擴展的拉丁字母,比如一些重音字母,帶音標的等等,所以,才設計出新的這個ISO/IEC 8859來支持這些字符。

最終設計出來的ISO/IEC 8859的字符集,支持很多歐洲的語言,包括丹麥語、荷蘭語、德語、意大利語、拉丁語、挪威語、葡萄牙語、西班牙語,瑞典語等。

2.2.2.2. ISO/IEC 8859的編碼規則

我們已經知道了,ASCII是7位的單字節編碼,其中0x20-0x7E的可見字符。

而ISO/IEC 8859,是在ASCII中的普通的可見字符(0x20-0x7E)的基礎上,利用了ASCII的7位編碼所沒有用到的第8位,這樣就編碼範圍就從原先ASCII的0x00-0x7F多擴展出了0x80-0xFF,其中的0xA0-0xFF部分,被ISO/IEC 8859編碼所用到。

有別於ASCII的單個獨立的編碼規則,ISO/IEC 8859是一組編碼規則的總稱,其下包含了共15個字符集,即ISO/IEC 8859-n,其中n=1,...,11,13,...,16。

關於這15種字符集是如何分類的,可以參考:表 A.2 “ISO/IEC 8859編碼標準中的15種字符集”

這15個字符集,每一個字符集,編碼取值都是0xA0-0xFF,但是對於同一個值,不同字符集所對應的字符,都不太一樣。

此處截取那15個字符集的其中一部分,以便更加直觀的瞭解不同字符集的區別:

圖 2.1. ISO/IEC 8859的15個字符集的部分比較

完整的字符表,請參見表 A.2 “ISO/IEC 8859編碼標準中的15種字符集”

  ASCII編碼有時候也會寫成ISO/IEC 8859-1編碼

另外,需要注意的是,對於原先的美國的英文字母,即普通的英語,其雖然沒有重音,音標等字母,但是由於其本身也還是包含在ASCII中,而ISO/IEC 8859-1包括了ASCII,所以,很多時候,對於英文字母來說,也仍會標明爲ISO/IEC 8859-1編碼。

2.2.2.3. ISO/IEC 8859的特點

對於ISO/IEC 8859所包含的全部字符,我們可以看到,對於基本的拉丁字母,那都是和ASCII一樣的,因爲其就是借用了ASCII中的0x20-0x7F這段的編碼,對應的是那些常見的可顯示的字符,而對於0xA0-0xFF這段空間,則是對於同一個值,不同的字符集中,對應着不同的符號。

對於ISO/IEC 8859的編碼方式是設計了多個字符集,我們不難看出,其之所以這麼編碼,而不是像ASCII中每個編碼值,都對應唯一的一個字符,那是因爲,歐洲的全部所用的字符數很多,如果是對於全部的歐洲用的字符都用一個對應的值來表示,那麼這剩下的0xA0-0xFF,甚至是0x80-0xFF,也都不夠用的,因爲0x80-0xFF128個值,當然不夠表示歐洲那幾百上千的不同國家的不同字符。

所以,纔會去設計出這麼15個字符集,然後對於同一個值,你用了ISO/IEC 8859-n,就表示對應的字符集中的那個特定的字符。

而上述做法的好處是,可以避免去用多個字節,比如兩個字節(8×2=16位,可以表示最多2^16=65536個字符)去表示一個單獨的字符,即節省了存放數據的空間。

但是缺點是,比如你寫一篇文章,中間出現了多個不同語系的不同的字符,那麼此文章如果用ISO/IEC 8859來編碼的話,那麼就無法單獨存成某一種對應的字符集,即包含多個歐洲國家不同語系的特殊字符的數據,無法用ISO/IEC 8859的某一個單獨的字符集來表示出來,即無法在同一個文章中支持顯示不同語系的不同的字符。

當然,相對於亞洲字符,即中文,日文,韓文等字符來說,另外一個如果算的上是缺點的話,那就是沒有把咱亞洲字符考慮進去。

正因此,字符編碼,纔會繼續演化出更加通用的,包含了世界上所有的字符的字符編碼標準:Unicode。

關於Unicode的詳細解釋請去看:第 2.4 節 “支持世界上幾乎所有字符的字符編碼:Unicode”

此處先來說說,其他幾個和ISO/IEC 8859相關的內容。

2.2.2.4. ISO/IEC 6429

可以看到,對應的ASCII編碼取值範圍是0x0-0x7F,而ISO/IEC 8859雖然是8位的單字節的編碼,但是隻是除了ASCII的0x20-0x7E之外,只是指定了0xA0-0xFF,而中間還有一段的值,即0x80-0x9F,卻沒有定義。

對此部分,是對應的ISO/IEC 6429編碼標準所定義的,此標準還定義了0x0-0x1F,即ASCII中的控制字符。

即,ISO/IEC 6429是專門定義對應的控制字符的,其中,0x0-0x1F部分稱爲C0控制(C0 control )字符,0x80-0x9F部分稱爲C1控制(C1 control)字符。

對應的C0 control部分,和ASCII編碼重複定義了,但是兩者含義都是一樣的,所以編碼規則並不衝突。

可以算是,在控制字符領域,ISO/IEC 6429在ASCII的C0 control的基礎上,對於由ASCII的7位所擴展出的8位編碼中的0x80-0x9F這部分,也做出了對應的定義。

簡言之:

ISO/IEC 6429

= 0x0-0x1F + 0x80-0x9F

=7位編碼ASCII中的0x0-0x1F + 擴展8位編碼中的0x80-0x9F

=C0 control + C1 control

2.2.2.5. ISO 8859和ISO-8859的區別和聯繫

ISO 8859和ISO-8859,不是同一個東西。

注意,後者是ISO和8859中間帶了一個小橫短線的。

前者,ISO 8859是ISO/IEC 8859標準集合的簡稱,對應包含了 ISO/IEC 8859-n,其中n爲除去2之外的1到16,這共15種字符集合。

ISO-8859,是ISO-8859-n的簡稱,是IANA根據ISO/IEC 8859-n的標準,加上對應的前面提到的普通的ASCII字符,和ISO/IEC 6429所定義的的控制字符,所制定的標準。

其中,由於ASCII中也包含了0x00-0x1F的控制字符,所以和ISO/IEC 6429中的C0控制字符重複了,但是兩者定義都是一樣的,所以從字符編碼上來說,不會產生任何衝突。

因此,ISO-8859-n所以可以表示:

ISO-8859

= ISO-8859-n的簡稱

= ISO 8859-n + ASCII + ISO/IEC 6429

其中,n=1,...,11,13,...,16,共15種編碼集合。

對應的,ISO 8859-1和ISO-8859-1兩者當前也是不一樣的,其區別也是:

ISO-8859-1

= ISO 8859-1 + ASCII + ISO/IEC 6429

= ISO/IEC 8859-1 + ASCII + ISO/IEC 6429

2.2.2.5.1. 原先的ISO 8859-1和我們常說的ISO 8859-1

原先的ISO 8859-1即ISO/IEC 8859-1,其編碼前面已經介紹過了,此處只是給出對應的字符表:

圖 2.2. ISO/IEC 8859-1字符集表

其中綠色的部分,就是原先ISO 8859-1中未定義的部分。而這部分,之前已經解釋了,是在另外的一個標準ISO/IEC 6429中定義的。

此處,需要注意的是,目前大家最常見的,提到最多的ISO 8859-1,實際多數都是指的是ISO-8859-1,即,是那個,既整合了0x20-0x1F這部分的普通的可以顯示的ASCII字母(基本的拉丁字母),又包含了對應的控制字符( C0 control和C1 control),同時也包含了歐洲多數國家所用到那些字符(擴展的拉丁字母,即ISO/IEC 8859-1中所定義的那些字符)。

總結起來就是:

常說的ISO 8859-1

= 實際上是ISO-8859-1

= ASCII + ISO/IEC 6429 + ISO 8859-1

= ASCII + ISO/IEC 6429 + ISO/IEC 8859-1

= (0x20-0x1F) + (0x0-0x1F + 0x80-0x9F) + (0xA0-0xFF)

= ASCII中的可見字符 + C0和C1的控制字符 + 歐洲多國所用的擴展的拉丁字符

2.3. 各種單字節編碼標準的關係

不論是ASCII的7位的編碼,還是後期演化出來的ISO/IEC 8859的8位的編碼,都還是用單個字節就可以表示一個字符,叫做單字節編碼。

各種單字節編碼之間的關係,可以用下面圖表來解釋:

表 2.2. 各種單字節編碼標準之間的關係

單字節編碼 單個字節=8位=28=256個字符
編碼標準 註釋 用到了前7位=27=128個字符 用到了第8位
0x0-0x1F 0x20-0x7E 0x7F 0x80-0x9F 0xA0-0xFF
ASCII =ISO/IEC 646 yes yes yes    
ISO/IEC 6429 =C0 control + C1 control yes     yes  
ISO 8859
=ISO/IEC 8859-n
=
ISO/IEC 8859-1
......
ISO/IEC 8859-11
ISO/IEC 8859-13
......
ISO/IEC 8859-16
  yes     yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
ISO-8859
=ISO-8859-n
=
ISO-8859-1
......
ISO-8859-11
ISO-8859-13
......
ISO-8859-16
yes yes yes yes yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes


0x20是空格Space,常縮寫爲SP。

此空格字符,嚴格意義上說,屬於不可顯示字符,因爲顯示或打印出來,也看不見

2.4. 支持世界上幾乎所有字符的字符編碼:Unicode

好了,介紹完了ISO/IEC 8859的種種,這下可以開始介紹Unicode了。

前面已經提到了,由於隨着計算機的發展,自然會發展到亞洲各國和其他一些地方,然後這些國家也遇到同樣問題,即如何把自己的國家的字符,顯示到對應的屏幕上。

2.4.1. Unicode和ISO 10646的關係

Unicode這個詞的中文翻譯,有譯爲萬國碼,單一碼,標準萬國碼,但是最常見的翻譯還是統一碼。

2.4.1.1. ISO 10646=UCS

國際標準組織ISO,定義了對應的編碼標準ISO/IEC 10646,簡稱爲ISO 10646,此標準所定義的字符集,稱作爲通用字符集(Universal Character Set,UCS)。

並不是所有的系統都需要支持像組合字符這樣的的先進機制。

因此ISO 10646指定了如下三種實現級別:

  1. 級別1:不支持組合字符和諺文字母字符。
  2. 級別2:類似於級別1,但在某些文字中,允許一列固定的組合字符,因爲如果沒有最起碼的幾個組合字符,UCS就不能完整地表達這些語言。
  3. 級別3:支持所有的通用字符集字符,如,可以在任意一個字符上加上一個箭頭或一個鼻音化符號

即,對於多數的實際使用中,並不一樣要求你實現包括世界上所有的字符,那就不一定非的要實現對應的第三級別,很多時候只需要實現第一級別就足夠涵蓋平常所用到的大部分的字符了。

我們平時會看到UCS-2,UCS-4,就是對應的ISO 10646標準中所定義的,對應的用2個字節或4個字節去表示同一個字符。

2.4.1.2. Unicode 和ISO 10646的聯繫

歷史上存在兩個獨立的嘗試創立單一字符集的組織,即國際標準化組織(ISO)和多語言軟件製造商組成的統一碼聯盟。

前者開發的 ISO/IEC 10646 項目,後者開發的Unicode項目。

因此最初制定了不同的標準。

1991年前後,兩個項目的參與者都認識到,世界不需要兩個不兼容的字符集。於是,它們開始合併雙方的工作成果,併爲創立一個單一編碼表而協同工作。從Unicode 2.0開始,Unicode採用了與ISO 10646-1相同的字庫和字碼;ISO也承諾,ISO 10646將不會超出U+10FFFF的UCS-4編碼賦值,以使得兩者保持一致。

兩個項目仍都存在,並獨立地公佈各自的標準,但統一碼聯盟和ISO/IEC JTC1/SC2都同意保持兩者標準的碼錶兼容,並緊密配合以保證之後的擴展也一致。

其各自的標準之間的對應關係如下:

表 2.3. ISO/IEC 10646與Unicode的版本對應關係

ISO/IEC 10646版本 Unicode版本
ISO/IEC 10646-1:1993 Unicode 1.1
ISO/IEC 10646-1:2000 Unicode 3.0
ISO/IEC 10646-2:2001 Unicode 3.2
ISO/IEC 10646:2003 Unicode 4.0
ISO/IEC 10646:2003 plus Amendment 1 Unicode 4.1
ISO/IEC 10646:2003 plus Amendment 1, Amendment 2, and part of Amendment 3 Unicode 5.0
ISO/IEC 10646:2003 plus Amendments 1 to 4 Unicode 5.1
ISO/IEC 10646:2003 plus Amendments 1 to 6 Unicode 5.2
ISO/IEC 10646:2011 Unicode 6.0

2.4.1.3. Unicode和ISO 10646的區別

統一碼聯盟公佈的Unicode標準包含了ISO/IEC 10646-1實現級別3的基本多文種平面BMP。在兩個標準裏,所有的字符都在相同的位置並且有相同的名字。

ISO/IEC 10646標準,就像ISO/IEC 8859標準一樣,只不過是一個簡單的字符集表。它定義了一些編碼的別名,指定了一些與標準有關的術語,幷包括了規範說明,指定了怎樣使用UCS連接其他ISO標準的實現,比如ISO/IEC 6429和ISO/IEC 2022。還有一些與ISO緊密相關的,比如ISO/IEC 14651是關於UCS字符串排序的。

Unicode標準,額外定義了許多與字符有關的語義符號學。Unicode詳細說明了繪製某些語言(如阿拉伯語)表達形式的算法,處理雙向文字(比如拉丁文和希伯來文的混合文字)的算法,排序與字符串比較所需的算法,等等。

所以,可以理解爲,ISO 10646中定義了編碼規則,定義了哪些值對應了哪些字符,而Unicode不僅定義了這些編碼規則,還定義了其他一些關於文字處理的細節算法等內容。

即:

Unicode

= ISO 10646的編碼規則 + 某些語言的細節處理算法

對於一般人來說,Unicode 和 ISO 10646,雖然兩者有些細節的區別,但是我們多數不用去關係這點細節內容,而對於字符編碼規則方面,此處可以簡單的理解爲:

Unicode

= ISO 10646編碼標準

= 標準所制定的UCS字符集

2.4.2. Unicode編碼規則

爲了將世界上幾乎所有的字符都涵蓋了,那麼就要了解世界上,有哪些字符。

除了之前ASCII的拉丁字母,ISO 8859所包含的歐洲多國用的字符之外,亞洲一些國家,包括中文,日文,韓文等,尤其是中文,包含的字符數,大概有幾萬個。

因此,Unicode的編碼就要設計的把這麼多的字符都包含在內。

Unicode的編碼方式與上面提到的ISO 10646的UCS概念相對應,目前實際應用的Unicode版本對應於UCS-2,即2字節的UCS字符集,使用16位的編碼空間。每個字符佔用2個字節,這樣理論上一共最多可以表示2^16=65536個字符。基本滿足各種語言的使用。實際上目前版本的Unicode尚未填充滿這16位編碼,保留了大量空間作爲特殊使用或將來擴展。

上述16位Unicode字符構成基本多文種平面(Basic Multilingual Plane,簡稱BMP)。最新(但未實際廣泛使用)的Unicode版本定義了16個輔助平面,兩者合起來至少需要佔據21位的編碼空間,比3字節略少。但事實上輔助平面字符仍然佔用4字節編碼空間,與UCS-4保持一致。未來版本會擴充到ISO 10646-1實現級別3,即涵蓋UCS-4的所有字符。

UCS-4是一個更大的尚未填充完全的31位字符集,加上恆爲0的首位,共需佔據32位,即4字節。理論上最多能表示2^31=2147483648=21億左右個字符,完全可以涵蓋一切語言所用的符號。

具體的取值範圍和所對應的平面空間劃分,參見圖 2.3 “Unicode中的各種平面劃分”

圖 2.3. Unicode中的各種平面劃分

Unicode中的0-0xFFF的BMP中的任何一個編碼的值,稱爲碼點(Code Point),對應用U+hhhh來表示,其中每個h 代表一個十六進制數位。

與UCS-2編碼完全相同。對應的4字節UCS-4編碼後兩個字節一致,前兩個字節的所有位均爲0。

2.4.3. Unicode字符編碼所對應的存儲和交換標準:UTF-8, UTF-16, UTF-32

需要注意的是,Unicode只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。

比如,漢字“嚴”的Unicode是十六進制數4E25,轉換成二進制數足足有15位(100111000100101),也就是說這個符號的表示至少需要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚至更多。

這裏就有兩個嚴重的問題,第一個問題是,如何才能區別Unicode和ASCII?計算機怎麼知道三個字節表示一個Unicode中的字符,而不是分別表示三個ASCII的 字符呢?第二個問題是,我們已經知道,英文字母只用一個字節表示就夠了,如果Unicode統一規定,每個符號用三個或四個字節表示,那麼每個英文字母前都必然有二到三個字節是0,這對於存儲來說是極大的浪費,文本文件的大小會因此大出二三倍,這是無法接受的。

它們造成的結果是:

  1. 出現了Unicode的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示Unicode
  2. Unicode在很長一段時間內無法推廣,直到互聯網的出現

2.4.3.1. UTF-8

互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8就是在互聯網上使用最廣的一種Unicode的實現方式。其他實現方式還包括UTF-16和UTF-32,不過在互聯網上基本不用。

重複一遍,這裏的關係是,UTF-8是Unicode的實現方式之一。

UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。

UTF-8的編碼規則很簡單,只有二條:

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

下表總結了編碼規則,字母x表示可用編碼的位。

表 2.4. Unicode與UTF-8之間的編碼映射關係

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編碼。

已知“嚴”的Unicode是4E25(100111000100101),根據上表,可以發現4E25處在第三行的範圍內(0000 0800-0000 FFFF),因此“嚴”的UTF-8編碼需要三個字節,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然後,從“嚴”的最後一個二進制位開始,依次從後向前填入格式中的x,多出的位補0。這樣就得到了,“嚴”的UTF-8編碼是“11100100 10111000 10100101”,轉換成十六進制就是E4B8A5。

2.4.3.2. Unicode與UTF-8之間的轉換

通過上一節的例子,可以看到“嚴”的Unicode碼是4E25,UTF-8編碼是E4B8A5,兩者是不一樣的。它們之間的轉換可以通過程序實現。

在Windows平臺下,有一個最簡單的轉化方法,就是使用內置的記事本小程序Notepad.exe。打開文件後,點擊"文件"→"另存爲"會跳出一個對話框,在最底部有一個"編碼"的下拉條:

圖 2.4. Notepad中的各種編碼

裏面有四個選項:ANSI,Unicode,Unicode big Endian 和 UTF-8:

  • ANSI是默認的編碼方式。對於英文文件是ASCII編碼,對於簡體中文文件是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會採用Big5碼)。
  • Unicode編碼指的是UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。這個選項用的Little Endian格式
  • Unicode Big Endian編碼與上一個選項相對應

    關於Little Endian和Big Endian,可以參考大端(Big Endian)與小端(Little Endian)詳解

  • UTF-8編碼,也就是上一節談到的編碼方法

選擇完”編碼方式“後,點擊”保存“按鈕,文件的編碼方式就立刻轉換好了。

下面,舉一個實例:

打開”記事本“程序Notepad.exe,新建一個文本文件,內容就是一個”嚴“字,依次採用ANSI,Unicode,Unicode big Endian 和 UTF-8編碼方式保存。

然後,用文本編輯軟件UltraEdit的”十六進制功能“,觀察該文件的內部編碼方式。

  • ANSI

    文件的編碼就是兩個字節“D1 CF”,這正是“嚴”的GB2312編碼,這也暗示GB2312是採用大頭方式存儲的

  • Unicode

    編碼是四個字節“FF FE 25 4E”,其中“FF FE”表明是小頭方式存儲,真正的編碼是4E25。

  • Unicode big Endian

    編碼是四個字節“FE FF 4E 25”,其中“FE FF”表明是大頭方式存儲。

  • UTF-8

    編碼是六個字節“EF BB BF E4 B8 A5”,前三個字節“EF BB BF”表示這是UTF-8編碼,後三個“E4B8A5”就是“嚴”的具體編碼,它的存儲順序與編碼順序是一致的

2.4.3.2.1. 關於UTF-8的BOM:“EF BB BF”

對於UTF-8的BOM(Byte Order Mark),即“EF BB BF”,是對於UTF-8編碼,微軟自己添加的,由此,會導致和其他很多軟件等不兼容。而Unicode標準中,也不推薦此給UTF-8添加“EF BB BF”的BOM。

剛去測試了一下,在Window XP中,將中文漢字“嚴”在記事本中另存爲UTF-8之後,用Notepad++去查看其十六進制的值,的確是“EF BB BF E4 B8 A5”,然後手動刪除了“EF BB BF”的BOM,保存後,再去用記事本打開,發現沒了BOM的UTF-8,記事本也是可以正確顯示出“嚴”字的。所以,結論是:

  1. 給UTF-8加“EF BB BF”的BOM,是微軟自己的做法,即微軟發現編碼是UTF-8的話,會給文件最開始加上“EF BB BF”
  2. Unicode的官方標準,不推薦這種做法,即不推薦給UTF-8加“EF BB BF”的BOM
  3. 所以,其他人寫軟件處理文字編碼的話,最好不要給UTF-8加BOM。當然,如果你非得要兼容微軟的做法,那麼去解析不同編碼的文件的話,針對UTF-8編碼,就要考慮這個特殊的的BOM了

更多關於BOM的解釋,參見第 2.7 節 “BOM”

2.5. 代碼頁Code Page

2.5.1. 什麼是代碼頁(Code Page)

Code Page,是字符編碼的另一種說法。

Code Page包含了一個表,表中的值,用於表示針對某種語言所用的字符集。

更簡單點說,就是Code Page中,用一個數字編號,表示了所要採用何種字符編碼,去編解碼相應的值,用於正確顯示出相應的字符。

Code Page這一概念,源於IBM,後被其他常見廣泛採用,包括Microsoft,SAP,Oracle等。

這些常見,各自定義了一套自己的Code Page,給每一個code page號,指定一個字符編碼。

比如,對於衆所周知的UTF-8編碼,在IBM的Code Page中編號是1208,在微軟中是65001,在SAP中是4110。

接下來,主要介紹大家最常見的Windows的Code Page

2.5.2. Windows中的Code Page

如前所述,Windows中也有自己的一套Code Page的定義。

用對應的某個數字,Code Page Number,即Code Page中的標識符(Identifier),表示相應的字符編碼。

而一般Code Page也常縮寫爲CP

比如,CP936表示GBK中文編碼,CP65001表示UTF-8編碼,CP54936表示GB18030編碼,CP950表示BIG5繁體中文等等。

  C#中使用當前系統默認編碼處理字符

對於C#來說,處理字符時涉及可能在不同環境中使用的話,那麼最好用系統默認編碼:

StreamReader reader = new StreamReader(path, System.Text.Encoding.Default);

2.5.2.1. Windows中的Code Page分類:ANSI和OEM

Windows中的Code Page,按照引用領域來劃分,可以分爲兩類:ANSI Code Page和 OEM Code Page

2.5.2.1.1. Windows的ANSI Code Page表

ANSI Code Page的官網正式叫法其實是Windows Code Page。但是由於ANSI Code Page被誤用的太廣泛了,索性微軟也就接受了此叫法,然後就叫做ANSI Code Page了。

類似地,ANSI Code Page=ANSI Windows Code Page

  Windows的Code Page爲何被誤稱爲ANSI Code Page

Windows的Code Page中用的最廣泛的是Windows 1252,其用於英語和西歐語言字符。

Windows 1252是基於ANSI草案(ANSI draft)而設計的。

結果,本來叫做Windows Code Page,就被很多不熟悉的人誤讀爲ANSI Code Page

而實際上,(作爲標準制定者的)ANSI和ISO,都從來沒有去標準化Windows的Code Page,即沒有爲Windows Code Page指定過任何標準。

但是呢,由於ANSI Code Page被誤用的太普遍了,導致微軟官方也都承認此叫法了。

總之,記住一點,ANSI Code Page,就是Windows Code Page,就行了。

ANSI Code Page主要是用於Windows系統中,本地編碼是非Unicode的,圖形用戶界面(GUI)程序。

ANSI的Code Page相關的表格,參見第 A.3.1.1 節 “ANSI Code Page表”

2.5.2.1.2. Windows的OEM Code Page表

OEM Code Page主要是用於Windows系統中的命令行界面(console)程序,虛擬DOS。

OEM Code Page可以視爲是DOS和IBM PC時代的(過渡)剩餘產品。

除了ANSI Code Page之外,之所以又設計出一個OEM Code Page,是因爲:

  1. 兼容性

    因爲作爲新的圖形用戶界面系統的Windows,也要兼容舊的命令行程序,即向後兼容性。

  2. 字體和硬件的要求

    字體和舊的VGA硬件建議,文字圖形界面所用的編碼,最好和Code Page 437兼容。

    多數的OEM的Code Page,和(非ASCII的)後半部分的CP437,都是公用同一套代碼點(code point)的。

    一般的OEM Code Page的後半段編碼,和ANSI Code Page,完全不同。不過,對於部分雙字節編碼的,定長的Code Page(如泰語的847,越南語的1258)和多字節CJK編碼的Code Page(如932,936,949,950)來說,ANSI和OEM的Code Page,都用的同一套編碼。

和OEM Code Page相關的表格,參見第 A.3.1.2 節 “OEM Code Page表”

2.5.2.1.3. 一些常見的Code Page表

其中,ANSI和OEM共有的一些Code Page,可參見第 A.3.1.3 節 “ANSI和OEM共有的Code Page表”

而其他一些常見的Code Page,可參見第 A.3.1.4 節 “其他一些常見的Code Page表”

2.5.2.2. 所有的Code Page表

除了ANSI和OEM,以及ANSI,OEM共有的Code Page之外,其他還有很多Code Page定義。

關於所有的Windows中的Code Page的定義,可在微軟官網[24]中找到。

此處已收錄至第 A.3.2 節 “所有的Code Page相關的表格”,以方便查閱。

2.6. ANSI字符編碼

2.6.1. ANSI是啥

ANSI,本身是American National Standards Institute的縮寫,中文翻譯爲美國國家標準學會

ANSI是個非營利組織,其負責制定美國國家標準。

2.6.2. ANSI編碼規則

ANSI字符編碼的規則,或者是其所包含的字符的由來,主要是:

  1. 0-127 (0x00-0x7F)

    完全和7位編碼的ASCII字符集(ASA X3.4-1963)相同

  2. 128-159 (0x80-0x9F)

    一些可打印字符

    這部分的編碼,與國際編碼ISO 8859-1的做法不同,ISO 8859-1是將此部分編碼用於控制字符

  3. 160-255 (0xA0-0FF)

    參考了ISO 8859-1中的字符

由此可以看出,ANSI中很多字符,和ISO-8859中的字符,看起來非常相似。

這就導致了很多人誤以爲,ANSI和ISO-8859是一回事呢。

總結:

ANSI

= Windows Code Page 1252

= Windows Codepage 1252

= Windows 1252

= CP 1252

= 共256個字符

= 0-127的ASCII + 128-159的可打印字符 + 160-255的和ISO 8859-1中類似的字符

2.6.3. ANSI (Windows 1252)編碼表

關於ANSI(Windows 1252)編碼表格,可以參考:

[20]

[35]

2.6.4. ANSI編碼與ANSI的關係

既然ANSI負責制定美國的國標,而在計算機方面,由於計算機最早是從美國最開始發展的,相應的所用到的字符編碼方面,ANSI也制定了對應的標準,所以就叫做ANSI字符編碼/ANSI字符集,英文爲ANSI Code/ANSI Encoding/ANSI set/ANSI charset

2.6.5. ANSI字符編碼和Windows 1252

Windows爲了支持英語和西歐字符,自己設計了一個編碼,對應的在Code Page號是1252,被稱爲Windows 1252。

Windows 1252的設計,是參考了ANSI草案(ANSI Draft)。

而ANSI draft後來發展成爲正式的國際標準:ISO 8859-1

即,Windows 1252是在其成爲正式標準ISO 8859-1之前而設計的,因此很容易理解,Windows 1252和ISO 8859-1不是完全等同的。

下面就來簡要說說兩者的區別。

2.6.5.1. Windows 1252和ISO 8859-1之間的區別

Windows 1252和ISO 8859-1基本等同

有點不同的是,在128-159(0x80-0x9F)的範圍的值,ISO 8859-1編碼爲控制字符,而微軟編碼爲可打印字符。

  提示
  1. 類似Windows的Code Page爲何被誤稱爲ANSI Code Page,Windows 1252也被誤稱爲ANSI編碼,所以此處也可以說是ANSI編碼和ISO 8859-1之間的區別。
  2. 而由於ISO 8859-1對應的Latin-1的西歐語言,所以此處也可以稱爲ANSI編碼和ISO Latin-1之間的區別,比如[19]
  3. 微軟的此種變體,有各種叫法:ANSI/Windows-1252/Windows Latin-1

    甚至有些微軟的程序將其叫做Western European (Windows)。

    更有甚至,由於不清楚,而錯稱其爲ASCII

  注意

因此,如果你把包含了128-159範圍內的ISO Latin-1編碼的文件,用Windows的記事本Notepad去另存爲爲ANSI的話,則會導致文件內容被錯誤處理了。

因爲本身的那些128-159的字符,是控制字符,但是卻被Notepad識別爲可打印的字符了。

總之,對於Windows 1252,目前的各種叫法,可以理解爲:

ANSI = Windows 1252 = CP 1252 = Windows code page 1252 = Windows Latin-1

2.6.6. 爲何"ANSI編碼"(在Windows中)被稱爲"本地編碼"

先說一下本地編碼,所謂本地編碼,即當前Windows中的二進制的值,用何種編碼去解析,然後顯示出對應的該編碼中的字符。

即,當然系統使用什麼類型的編碼。

而ANSI編碼,根據前面內容得知,只是一個普通的對應於Windows 1252的一個編碼而已。並不是其他某些編碼合集的總稱。

但是有時候,卻又看到有人把ANSI編碼解釋爲“本地編碼”,比如[22]

其意思,就是[30]中所說的,Windows code pages有時又被稱爲"active code pages","system active code pages"。

而作爲微軟用A表示ANSI版本的函數,W表示Wide,Unicode版本的函數,此時所有的A版本的函數,就都用的是當前有效的Code Page,即"本地編碼"了

其中,Windows系統中,當前有且只有一個active Windows code page。

也就意味着,此處所謂的ANSI編碼,就相當於之前所說的Code Page了,即當前系統採用何種編碼去解析字符

也就是你當前系統中設置的本地編碼爲何種編碼,然後系統中,遇到需要解析的字符,就按照你所設置的本地編碼去解析了。

比如,本身對於中文GBK編碼的字符,如果你本地編碼設置爲UTF-8,那麼按照UTF-8編碼去解析出來的GBK字符,當前就是亂碼了。

而只有正確設置爲GBK,才能正確解析原本就是GBK編碼後的字符,才能正確顯示出中文。

同理,用GBK編碼去解析原本用UTF-8編碼後的字符,也會導致亂碼。

  提示

這種亂碼問題,常常會在和編碼打交道的事情中遇到

比如Python中在命令行cmd中打印輸出字符串,如果本身字符串是GBK編碼的,那麼你的cmd中的本地編碼,就要設置爲是936 (ANSI/OEM - Simplified Chinese GBK),這樣中文字符才能正確顯示。

當然,如果你本身輸出的字符中,即包含UTF-8編碼的字符,又包含GBK編碼的字符,那麼則是無論如何設置,都是無法同時正常顯示的。除非你轉換爲Unicode編碼,然後讓Python輸出函數自動處理,纔可以正確顯示。

2.7. BOM

2.7.1. BOM是什麼

BOM是一個Unicode字符。

BOM用於指示文件/字符流的大小端(字節序)。

不同編碼所對應的BOM不同。

2.7.2. 爲何需要BOM

即使對於字符進行了某種編碼,可以正確讀取/寫入,可以正常顯示字符了。

但是遇到將一個文件/字符流,從一個地方傳輸到另一個地方的話,就會遇到一些問題:

比如,本地是一個用UTF-16 LE編碼的文件,傳入到網絡的另一端,接受者怎麼知道你用的是UTF-16 LE的編碼,而不是UTF-16 BE呢?

如果不知道,用了錯誤的UTF-16 BE去解碼,且不是會導致亂碼問題了。

所以,就需要一個說明和解釋,目前的做法就是,在文件頭(字符流的開始),添加一個BOM,Byte Order Mark,字節序的標記,用於表示此編碼是LE還是BE。

2.7.3. BOM表

相關的不同編碼所用的BOM,參見摘錄自[36]表 A.8 “不同編碼所用的BOM”

關於UTF-8的BOM: EF BB BF,可參考第 2.4.3.2.1 節 “關於UTF-8的BOM:“EF BB BF””

2.8. 中文字符編碼標準

2.8.1. GB2312,CP936,GBK,GB18030,GB13000

2.8.1.1. GB2312

1980年,中國製定了GB2312-80,一共收錄了 7445 個字符,包括 6763 個漢字和 682 個其它符號。

GB2312-80,簡稱爲GB2312。

在 Windows 中的代碼頁(Code Page)是 CP936。

2.8.1.2. GB13000

1993年,國際標準Unicode 1.1版本推出,收錄中國大陸、臺灣、日本及韓國通用字符集的漢字,總共有20,902個。

中國大陸訂定了等同於Unicode 1.1版本的“GB 13000.1-93”,簡稱爲GB13000。

GB13000,顯然包含的GB2312已有的文字和其他很多爲包含的文字,如GB 2312-80推出以後才簡化的漢字(如“囉”),部分人名用字(如中國前總理朱鎔基的“鎔”字),臺灣及香港使用的繁體字,日語及朝鮮語漢字等。

2.8.1.3. GBK

微軟,對GB2312-80的擴展,即利用GB 2312-80未使用的編碼空間,收錄所有的GB 13000.1-93和Unicode 1.1之中的漢字全部字符,制定了GBK編碼。

GBK 收錄了 21886 個符號,它分爲漢字區和圖形符號區。漢字區包括 21003 個字符。

GBK 作爲對 GB2312 的擴展,在現在的 Windows 系統中仍然使用代碼頁 CP936 表示,但是同樣的 936 的代碼頁跟一開始的 936 的代碼頁只支持 GB2312 編碼不同,現在的 936 代碼頁支持 GBK 的編碼,GBK 同時也向下兼容GB2312 編碼。

所以,技術編碼上,GBK兼容舊的GB2312,但是編碼方式和GB13000不同,不兼容GB13000,但是所包含文字上,算是和GB13000相同。

2.8.1.4. GB18030

GBK自身並非國家標準,只是曾由國家技術監督局標準化司、電子工業部科技與質量監督司公佈爲“技術規範指導性文件”。

原始GB13000一直未被業界採用,2000年,國家出了標準GB18030-2000,簡稱GB18030,技術上兼容GBK而非GB13000,取代了 GBK1.0,成了正式的國家標準。

該標準收錄了 27484 個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數民族文字。

現在的PC平臺必須支持 GB18030 ,對嵌入式產品暫不作要求。所以手機、MP3 一般只支持 GB2312。

GB18030 在 Windows 中的代碼頁是 CP54936。

這麼多漢字編碼標準的關係,總結起來就是第 2.8.2 節 “各種中文字符編碼標準的關係”中所介紹的。

2.8.2. 各種中文字符編碼標準的關係

( 中國大陸的標準)GB 13000.1-93

=(國際標準)Unicode 1.1

(中國大陸標準)GB2312-80

= 簡稱GB2312

= Windows系統中的原先的CP936

(微軟制定的)GBK

= (微軟在編碼方面)對 GB2312 的擴展

= (微軟在所包含字符方面上包含了)GB 13000.1-93 + 其他部分漢字+ 臺灣和香港的繁體 + 日語 + 朝鮮漢字

Unicode 1.1 + 其他部分漢字+ 臺灣和香港的繁體 + 日語 + 朝鮮漢字

對於GBK

  • 在編碼方面:向下兼容GB2312,但是和GB 13000不同
  • 在內容方面:等價於GB13000

微軟中現在的新的CP936

GBK

=兼容舊的GB2312

在技術編碼方面上,演化順序爲:

ASCII ⇒ GB2312 ⇒ GBK ⇒ GB18030

後者對之前的,都是支持之前的編碼,即向下兼容,即同一個字符,在這些編碼中,都是同樣的值,後面的標準,支持更多的字符。

區分中文編碼的方法是高字節的最高位不爲 0。

按照程序員的稱呼,GB2312、GBK 到 GB18030 都屬於雙字節字符集 (DBCS)

表 2.5. 中文字符相關編碼標準

編碼標準 別名 標準所屬 包含字符
ASCII   國際通用  
GB2312 微軟Windows中以前的CP936 中國大陸 6763 個漢字和 682 個其它符號
Unicode 1.1   國際通用 20,902個字符
GB13000   中國大陸 20,902個字符
GBK 微軟Windows中現在的CP936 微軟 21886 個符號
GB18030 微軟Windows中的CP54936 中國大陸 27484 個漢字+其他少數民族字符

2.9. 字符存儲(交換)標準

下表列出了常見的字符編碼的標準,及其對應的交換存儲時候所用的標準:

表 2.6. 字符(存儲)交換標準

字符編碼標準 存儲(交換/傳輸)標準
包含字符 字符編碼領域的叫法
英文
ASCII
==ISO/IEC 646
ASCII
歐洲多國的字符 ISO 8859  
通用(的任何)字符 Unicode UTF-8
UTF-16
UTF-32
簡體中文
GB2312
==GB2312-80
==GB
==GB0
EUC-CN
GBK
GB18030
繁體中文
BIG5
==大五碼
==五大碼
CCCII
CNS-11643
EUC-TW
日文
JIS X 0208
== JIS C 6226和JIS X 0212
Shift JIS
ISO-2022-JP
EUC-JP
JIS X 0213 EUC-JISX0213
韓文
KS X 1001
== KS C 5601
EUC-KR


UTF==Unicode Transformation Format==Unicode轉換格式


關於中文字符編碼的各種標準的演化,可以參考中文字符編碼標準+Unicode+Code Page


關於GB0,另外還有其他的GBn,也是關於中文的國家標準:

  1. GB1==GB/T 12345 – 90==《信息交換用漢字編碼字符集 第一輔助集》
  2. GB2==GB/T 7589 – 87==《信息交換用漢字編碼字符集 第二輔助集》
  3. GB3==GB 13131 – 91==《信息交換用漢字編碼字符集 第三輔助集》
  4. GB4==GB/T 7590 – 87==《信息交換用漢字編碼字符集 第四輔助集》
  5. GB5==GB 13132 – 91==《信息交換用漢字編碼字符集 第五輔助集》

關於GB的含義,即國標的首字母。其中,強制標準冠以“GB”,推薦標準冠以“GB/T”。


EUC==Extended Unix Code

2.10. 字形和你所看到的字符的關係

對於某個字符,其字形是固定的,是對應的字符編碼標準,即編碼集中所定義好了的。比如,入門的“入”,這一撇一捺,是連在一起的,你不能寫錯了,寫成左右分開的,那錯寫成了八個的“八”了。而這樣的字符的形狀,簡稱字形,是編碼中定義好的,你不能隨便亂寫。

但是同一個字符,具體的字體,大小等,則是按照自己喜好去設置的,是留給其他軟件來處理的,比如宋體的“宋”這個漢字,不同的字體,會顯示出來不同的效果:

圖 2.5. 漢字“宋”的不同字體


這樣的對於同一個字符的後期處理,即想要用什麼樣的字體,什麼樣的大小來顯示等,都是後期軟件,比如瀏覽器,微軟的word等文本編輯器中去設置的。

附錄 A. 編碼相關的表格

A.1. ASCII編碼表(0-127)

表 A.1. ASCII編碼表(0-127)

十六進制 十進制 字符 十六進制 十進制 字符 十六進制 十進制 字符 十六進制 十進制 字符
0 0 NUL 20 32 [space] 40 64 @ 60 96 '
1 1 SOH 21 33 ! 41 65 A 61 97 a
2 2 STX 22 34 " 42 66 B 62 98 b
3 3 ETX 23 35 # 43 67 C 63 99 c
4 4 EOT 24 36 $ 44 68 D 64 100 d
5 5 ENQ 25 37 % 45 69 E 65 101 e
6 6 ACK 26 38 & 46 70 F 66 102 f
7 7 BEL 27 39 ` 47 71 G 67 103 g
8 8 BS 28 40 ( 48 72 H 68 104 h
9 9 HT 29 41 ) 49 73 I 69 105 i
0a 10 LF 2a 42 * 4a 74 J 6a 106 j
0b 11 VT 2b 43 + 4b 75 K 6b 107 k
0c 12 FF 2c 44 , 4c 76 L 6c 108 l
0d 13 CR 2d 45 - 4d 77 M 6d 109 m
0e 14 SO 2e 46 . 4e 78 N 6e 110 n
0f 15 SI 2f 47 / 4f 79 O 6f 111 o
10 16 DLE 30 48 0 50 80 P 70 112 p
11 17 DC1 31 49 1 51 81 Q 71 113 q
12 18 DC2 32 50 2 52 82 R 72 114 r
13 19 DC3 33 51 3 53 83 S 73 115 s
14 20 DC4 34 52 4 54 84 T 74 116 t
15 21 NAK 35 53 5 55 85 U 75 117 u
16 22 SYN 36 54 6 56 86 V 76 118 v
17 23 ETB 37 55 7 57 87 W 77 119 w
18 24 CAN 38 56 8 58 88 X 78 120 x
19 25 EM 39 57 9 59 89 Y 79 121 y
1a 26 SUB 3a 58 : 5a 90 Z 7a 122 z
1b 27 ESC 3b 59 ; 5b 91 [ 7b 123 {
1c 28 FS 3c 60 < 5c 92 \ 7c 124 |
1d 29 GS 3d 61 = 5d 93 ] 7d 125 }
1e 30 RS 3e 62 > 5e 94 ^ 7e 126 ~
1f 31 US 3f 63 ? 5f 95 _ 7f 127 [delete]

A.2. ISO/IEC 8859編碼標準中的15種字符集

表 A.2. ISO/IEC 8859編碼標準中的15種字符集

ISO/IEC 8859-n 英文別名 中文解釋
ISO/IEC 8859 -1 Latin-1 西歐語言
ISO/IEC 8859 -2 Latin-2 中歐語言
ISO/IEC 8859 -3 Latin-3 南歐語言。世界語也可用此字符集顯示。
ISO/IEC 8859 -4 Latin-4 北歐語言
ISO/IEC 8859 -5 Cyrillic 斯拉夫語言
ISO/IEC 8859 -6 Arabic 阿拉伯語
ISO/IEC 8859 -7 Greek 希臘語
ISO/IEC 8859 -8 Hebrew 希伯來語(視覺順序);ISO 8859-8-I是 希伯來語(邏輯順序)
ISO/IEC 8859 -9 Latin-5 或 Turkish 它把Latin-1的冰島語字母換走,加入土耳其語字母
ISO/IEC 8859 -10 Latin-6 或 Nordic 北日耳曼語支,用來代替Latin-4
ISO/IEC 8859 -11 Thai 從泰國的 TIS620 標準字集演化而來
ISO/IEC 8859 -13 Latin-7 或 Baltic Rim 波羅的語族
ISO/IEC 8859 -14 Latin-8 或 Celtic 凱爾特語族
ISO/IEC 8859 -15 Latin-9 西歐語言,加入Latin-1欠缺的芬蘭語字母和大寫法語重音字母,以及歐元(€)符號。
ISO/IEC 8859 -16 Latin-10 東南歐語言。主要供羅馬尼亞語使用,並加入歐元符號。

A.3. Code Page表格

A.3.1. 常見的ANSI和OEM的Code Page的表格

A.3.1.1. ANSI Code Page表

ANSI Code Page中,字符編碼都是用的8位單字節,所以也被稱爲SBCS (Single Byte Character Set) Codepages,即單字節字符集的代碼頁

表 A.3. ANSI的SBCS Code Page

代碼頁Code Page 對應的字符集Character Set
Code Page 1250 Central and East European Latin
Code Page 1251 Cyrillic
Code Page 1252 West European Latin
Code Page 1253 Greek
Code Page 1254 Turkish
Code Page 1255 Hebrew
Code Page 1256 Arabic
Code Page 1257 Baltic
Code Page 1258 Vietnamese
Code Page 874 Thai

A.3.1.2. OEM Code Page表

OEM的Code Page如下:

表 A.4. OEM的Code Page

代碼頁Code Page 對應的字符集Character Set
Code Page 437 original IBM PC Code Page==USA
Code Page 720 Arabic
Code Page 737 Greek
Code Page 775 Estonian, Lithuanian and Latvian
Code Page 850 "Multilingual (Latin-1)" (Western European languages)
Code Page 852 "Slavic (Latin-2)" (Central and Eastern European languages)
Code Page 855 Cyrillic
Code Page 857 Turkish
Code Page 858 "Multilingual" with euro symbol
Code Page 860 Portuguese
Code Page 861 Icelandic
Code Page 862 Hebrew
Code Page 863 French (Quebec French)
Code Page 865 Danish/Norwegian Differs from 437
Code Page 869 Greek
Code Page 874 Thai

A.3.1.3. ANSI和OEM共有的Code Page表

ANSI和OEM共有Code Page,是一些DBCS (Double Byte Character Set) Codepages,即雙字節字符集的代碼頁。

表 A.5. ANSI和OEM共有的DBCS Code Page

代碼頁Code Page 對應的字符集Character Set
Code Page 932 Japanese
Code Page 936 GBK - Simplified Chinese
Code Page 949 Korean
Code Page 950 BIG5 - Traditional Chinese

A.3.1.4. 其他一些常見的Code Page表

其他一些常見的Code Page如下:

表 A.6. 一些常見的Code Page

代碼頁Code Page 對應的字符集Character Set
Code Page 1200 UTF-16LE Unicode little-endian
Code Page 1201 UTF-16BE Unicode big-endian
Code Page 65000 UTF-7 Unicode
Code Page 65001 UTF-8 Unicode
Code Page 10000 Macintosh Roman encoding (followed by several other Mac character sets)
Code Page 10007 Macintosh Cyrillic encoding
Code Page 10029 Macintosh Central European encoding
Code Page 20127 US-ASCII The classic US 7 bit character set with no char larger than 127
Code Page 28591 ISO-8859-1 (followed by ISO-8859-2 to ISO-8859-15)

A.3.2. 所有的Code Page相關的表格

表 A.7. 微軟的代碼頁標識符(Code Page Identifiers)

Identifier .NET Name Additional information
037 IBM037 IBM EBCDIC US-Canada
437 IBM437 OEM United States
500 IBM500 IBM EBCDIC International
708 ASMO-708 Arabic (ASMO 708)
709   Arabic (ASMO-449+, BCON V4)
710   Arabic - Transparent Arabic
720 DOS-720 Arabic (Transparent ASMO); Arabic (DOS)
737 ibm737 OEM Greek (formerly 437G); Greek (DOS)
775 ibm775 OEM Baltic; Baltic (DOS)
850 ibm850 OEM Multilingual Latin 1; Western European (DOS)
852 ibm852 OEM Latin 2; Central European (DOS)
855 IBM855 OEM Cyrillic (primarily Russian)
857 ibm857 OEM Turkish; Turkish (DOS)
858 IBM00858 OEM Multilingual Latin 1 + Euro symbol
860 IBM860 OEM Portuguese; Portuguese (DOS)
861 ibm861 OEM Icelandic; Icelandic (DOS)
862 DOS-862 OEM Hebrew; Hebrew (DOS)
863 IBM863 OEM French Canadian; French Canadian (DOS)
864 IBM864 OEM Arabic; Arabic (864)
865 IBM865 OEM Nordic; Nordic (DOS)
866 cp866 OEM Russian; Cyrillic (DOS)
869 ibm869 OEM Modern Greek; Greek, Modern (DOS)
870 IBM870 IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2
874 windows-874 ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows)
875 cp875 IBM EBCDIC Greek Modern
932 shift_jis ANSI/OEM Japanese; Japanese (Shift-JIS)
936 gb2312 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
949 ks_c_5601-1987 ANSI/OEM Korean (Unified Hangul Code)
950 big5 ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
1026 IBM1026 IBM EBCDIC Turkish (Latin 5)
1047 IBM01047 IBM EBCDIC Latin 1/Open System
1140 IBM01140 IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)
1141 IBM01141 IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)
1142 IBM01142 IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)
1143 IBM01143 IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)
1144 IBM01144 IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)
1145 IBM01145 IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)
1146 IBM01146 IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)
1147 IBM01147 IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)
1148 IBM01148 IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)
1149 IBM01149 IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)
1200 utf-16 Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications
1201 unicodeFFFE Unicode UTF-16, big endian byte order; available only to managed applications
1250 windows-1250 ANSI Central European; Central European (Windows)
1251 windows-1251 ANSI Cyrillic; Cyrillic (Windows)
1252 windows-1252 ANSI Latin 1; Western European (Windows)
1253 windows-1253 ANSI Greek; Greek (Windows)
1254 windows-1254 ANSI Turkish; Turkish (Windows)
1255 windows-1255 ANSI Hebrew; Hebrew (Windows)
1256 windows-1256 ANSI Arabic; Arabic (Windows)
1257 windows-1257 ANSI Baltic; Baltic (Windows)
1258 windows-1258 ANSI/OEM Vietnamese; Vietnamese (Windows)
1361 Johab Korean (Johab)
10000 macintosh MAC Roman; Western European (Mac)
10001 x-mac-japanese Japanese (Mac)
10002 x-mac-chinesetrad MAC Traditional Chinese (Big5); Chinese Traditional (Mac)
10003 x-mac-korean Korean (Mac)
10004 x-mac-arabic Arabic (Mac)
10005 x-mac-hebrew Hebrew (Mac)
10006 x-mac-greek Greek (Mac)
10007 x-mac-cyrillic Cyrillic (Mac)
10008 x-mac-chinesesimp MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)
10010 x-mac-romanian Romanian (Mac)
10017 x-mac-ukrainian Ukrainian (Mac)
10021 x-mac-thai Thai (Mac)
10029 x-mac-ce MAC Latin 2; Central European (Mac)
10079 x-mac-icelandic Icelandic (Mac)
10081 x-mac-turkish Turkish (Mac)
10082 x-mac-croatian Croatian (Mac)
12000 utf-32 Unicode UTF-32, little endian byte order; available only to managed applications
12001 utf-32BE Unicode UTF-32, big endian byte order; available only to managed applications
20000 x-Chinese_CNS CNS Taiwan; Chinese Traditional (CNS)
20001 x-cp20001 TCA Taiwan
20002 x_Chinese-Eten Eten Taiwan; Chinese Traditional (Eten)
20003 x-cp20003 IBM5550 Taiwan
20004 x-cp20004 TeleText Taiwan
20005 x-cp20005 Wang Taiwan
20105 x-IA5 IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)
20106 x-IA5-German IA5 German (7-bit)
20107 x-IA5-Swedish IA5 Swedish (7-bit)
20108 x-IA5-Norwegian IA5 Norwegian (7-bit)
20127 us-ascii US-ASCII (7-bit)
20261 x-cp20261 T.61
20269 x-cp20269 ISO 6937 Non-Spacing Accent
20273 IBM273 IBM EBCDIC Germany
20277 IBM277 IBM EBCDIC Denmark-Norway
20278 IBM278 IBM EBCDIC Finland-Sweden
20280 IBM280 IBM EBCDIC Italy
20284 IBM284 IBM EBCDIC Latin America-Spain
20285 IBM285 IBM EBCDIC United Kingdom
20290 IBM290 IBM EBCDIC Japanese Katakana Extended
20297 IBM297 IBM EBCDIC France
20420 IBM420 IBM EBCDIC Arabic
20423 IBM423 IBM EBCDIC Greek
20424 IBM424 IBM EBCDIC Hebrew
20833 x-EBCDIC-KoreanExtended IBM EBCDIC Korean Extended
20838 IBM-Thai IBM EBCDIC Thai
20866 koi8-r Russian (KOI8-R); Cyrillic (KOI8-R)
20871 IBM871 IBM EBCDIC Icelandic
20880 IBM880 IBM EBCDIC Cyrillic Russian
20905 IBM905 IBM EBCDIC Turkish
20924 IBM00924 IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
20932 EUC-JP Japanese (JIS 0208-1990 and 0121-1990)
20936 x-cp20936 Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)
20949 x-cp20949 Korean Wansung
21025 cp1025 IBM EBCDIC Cyrillic Serbian-Bulgarian
21027   (deprecated)
21866 koi8-u Ukrainian (KOI8-U); Cyrillic (KOI8-U)
28591 iso-8859-1 ISO 8859-1 Latin 1; Western European (ISO)
28592 iso-8859-2 ISO 8859-2 Central European; Central European (ISO)
28593 iso-8859-3 ISO 8859-3 Latin 3
28594 iso-8859-4 ISO 8859-4 Baltic
28595 iso-8859-5 ISO 8859-5 Cyrillic
28596 iso-8859-6 ISO 8859-6 Arabic
28597 iso-8859-7 ISO 8859-7 Greek
28598 iso-8859-8 ISO 8859-8 Hebrew; Hebrew (ISO-Visual)
28599 iso-8859-9 ISO 8859-9 Turkish
28603 iso-8859-13 ISO 8859-13 Estonian
28605 iso-8859-15 ISO 8859-15 Latin 9
29001 x-Europa Europa 3
38598 iso-8859-8-i ISO 8859-8 Hebrew; Hebrew (ISO-Logical)
50220 iso-2022-jp ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
50221 csISO2022JP ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)
50222 iso-2022-jp ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)
50225 iso-2022-kr ISO 2022 Korean
50227 x-cp50227 ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)
50229   ISO 2022 Traditional Chinese
50930   EBCDIC Japanese (Katakana) Extended
50931   EBCDIC US-Canada and Japanese
50933   EBCDIC Korean Extended and Korean
50935   EBCDIC Simplified Chinese Extended and Simplified Chinese
50936   EBCDIC Simplified Chinese
50937   EBCDIC US-Canada and Traditional Chinese
50939   EBCDIC Japanese (Latin) Extended and Japanese
51932 euc-jp EUC Japanese
51936 EUC-CN EUC Simplified Chinese; Chinese Simplified (EUC)
51949 euc-kr EUC Korean
51950   EUC Traditional Chinese
52936 hz-gb-2312 HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)
54936 GB18030 Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
57002 x-iscii-de ISCII Devanagari
57003 x-iscii-be ISCII Bengali
57004 x-iscii-ta ISCII Tamil
57005 x-iscii-te ISCII Telugu
57006 x-iscii-as ISCII Assamese
57007 x-iscii-or ISCII Oriya
57008 x-iscii-ka ISCII Kannada
57009 x-iscii-ma ISCII Malayalam
57010 x-iscii-gu ISCII Gujarati
57011 x-iscii-pa ISCII Punjabi
65000 utf-7 Unicode (UTF-7)
65001 utf-8 Unicode (UTF-8)

A.4. 不同編碼所用的BOM

表 A.8. 不同編碼所用的BOM

編碼類型 BOM值(16進制) BOM值(10進制)
UTF-8 EF BB BF 239 187 191
UTF-16 (BE) FE FF 254 255
UTF-16 (LE) FF FE 255 254
UTF-32 (BE) 00 00 FE FF 0 0 254 255
UTF-32 (LE) FF FE 00 00 255 254 0 0
UTF-7 2B 2F 76 38 43 47 118 56
2B 2F 76 39 43 47 118 57
2B 2F 76 2B 43 47 118 43
2B 2F 76 2F 43 47 118 47
UTF-1 F7 64 4C 247 100 76
UTF-EBCDIC DD 73 66 73 221 115 102 115
SCSU 0E FE FF 14 254 255
BOCU-1 FB EE 28 251 238 40
GB-18030 84 31 95 33 132 49 149 51

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