web開發(fā)中的字符集原理詳解

2010-11-15 10:23:16來源:作者:

1. Collations
Collations翻成中文是“校驗”,在網(wǎng)頁開發(fā)的過程中,這個詞匯,只在 Mysql里使用,主要作用是指導Mysql對字符的比較,比如, ASCII字符集里,Collations規(guī)定了a小于b,a等于a,以及a是否等于A之類的

1. Collations
Collations翻成中文是“校驗”,在網(wǎng)頁開發(fā)的過程中,這個詞匯,只在 Mysql里使用,主要作用是指導Mysql對字符的比較,比如, ASCII字符集里,Collations規(guī)定了a小于b,a等于a,以及a是否等于A之類的。通常,大家基本可以忽略Collations的存在,因為每個字符集都有一個默認的Collations,通常,使用默認的Collations就可以了。以字節(jié)為編碼單元,沒有字節(jié)序的問題。UTF-16以兩個字節(jié)為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節(jié)序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節(jié)流“594E”,那么這是“奎”還是“乙”?<o:p></o:p>

2.字符集
與這對比的是,字符集是個更廣的概念,即使是Windows下普通的文本文件,也滲及到字符集的問題。不同的字符集,規(guī)定了不同的字符的編碼方式。一個 character set (字符集)是一組符號和編碼,比如,ASCII字符集,包括的字符有:數(shù)字,大小寫字母,分號、換行之類的符號,編碼方式是用一個7bit表示一個字符(A的編碼是65,b的編碼是98)。ASCII只規(guī)定了英文字母的編碼,非英文語言不能用ASCII編碼表示,為此,不同的國家,都為自己的語言做了編碼,比如,我們國家,就有GB2312編碼。但每個國家之間的編碼不同,也存在著一些跨平臺的問題,為此,一些國際化標準組織,就制定了一些國際通用的編碼,最常用的就是UTF8了。ASCII只對英文符號和英文字母做了編碼,GB2312對英文符號,英文字母,漢字做了編碼,UTF8對世界上所有的語言文字做了編碼,所以,GB1212的字符包含了ASCII字符,UTF8包含了GB2312字符。由此可見,UTF8是所含最廣字符的字符集,所以,在一些多語言的WEB系統(tǒng)中,一般用UTF8字符集(PHPMyAdmin使用UTF8編碼)。
任何文本的存儲,都滲及到字符集的概念。包括數(shù)據(jù)庫,也包括普通的文本文件。
主要術(shù)語:
字符:漢字,英文字母,標點符號,拉丁文等等。
編碼:將字符轉(zhuǎn)換成計算機存儲的格式,比如,A用65表示
字符集:一組字符以及對應的編碼方式。

a. Mysql的字符集
Mysql目前支持多字符集,并且,支持在不同的字符集之間轉(zhuǎn)換(便于移植和支持多語言)。
Mysql可以設置服務器級字符集、數(shù)據(jù)庫級字符集、數(shù)據(jù)表級字符集、表列的字符集,實際上,最終使用字符集的地方是存儲字符的列,比如,你設置 table1中col1列是字符類型,col1才用到了字符集,如果table1表的col2列是int類型,col2不使用字符集的概念。
服務器級字符集、數(shù)據(jù)庫級字符集、數(shù)據(jù)表級字符集都是為列的字符集做默認選項的。
Mysql一定有一個字符集,可以通過啟動時加參數(shù)指定,也可以編譯時指定,也可以在配置文件里指定。Mysql服務器字符集,只是做為數(shù)據(jù)庫級的默認值。創(chuàng)建數(shù)據(jù)庫時,你可以指定字符集,如果沒指定,就使用服務器的字符集。同理,創(chuàng)建表時,你可以指定表級的字符集,如果沒指定,使用數(shù)據(jù)庫的字符集做為表的字符集。創(chuàng)建列時,你可以指定某列的字符集,如果沒指定,就使用表的字符集。
通常情況下,您只需設置服務器級的字符集,其它的數(shù)據(jù)庫級,表級,以及列級的字符集,都繼承自服務器級字符集。
由于UTF8是最廣的字符集,所以,一般情況下,我們設置Mysql服務器級的字符集為UTF8!

b. 普通文本的字符集問題
任何文本的存儲,都存在著字符集的問題,普通文本文件也不例外。
Windows2000+的系統(tǒng)中,打開記事本,“保存為…”對話框,就有一個選項,可以讓你選擇存儲文本的編碼方式。
通常情況下,大家都使用Windows2000+的系統(tǒng),都使用默認的編碼,所以,不會碰到字符集的問題。
Windows下,保存文本文件時,可以選擇編碼方式,但打開文本文件時,都是自動判斷編碼方式的。網(wǎng)上有一個用Windows2000+的記事本玩移動,聯(lián)通的笑話,大家可以搜搜,就是因為Windows在打開文本文件時,編碼判斷錯誤引起的問題。
因為自動判斷編碼有時會錯誤,所以,有的文本文件,規(guī)定了如何識別自身所使用的編碼。HTML文件就是一個這樣的例子。>
HTML是文本文件。存儲HTML文件的時候,需要使用一個編碼,并且,在HTML文件里,也使用HTML語法,指定了該文件所使用的編碼(比如< meta http-equiv="content-type" content="text/html; charset=UTF-8">)。如果HTML文件沒有指定編碼,則瀏覽器自動識別文件的編碼。如果HTML指定了編碼,則瀏覽器使用HTML指定的編碼。
通常情況下,HTML文件指定的charset和HTML文件自身的編碼是一致的,但也有不一致的情況,如果不一致,就會導致網(wǎng)頁亂碼(此處亂碼,只和文本文件有關,和數(shù)據(jù)庫無關。)使用專門的網(wǎng)頁編輯工具(比如Dreamwave),會自動根據(jù)網(wǎng)頁中的charset值來編碼文件。

c. php+mysql的字符集問題
PHP最終生成的是文本文件,但他要取數(shù)據(jù)庫里的文本,或?qū)⑽谋敬孢M數(shù)據(jù)庫
由于Mysql支持多字符集,默認情況下,Mysql不知道PHP發(fā)給他的是什么編碼的字符,所以,Mysql要求客戶端(PHP)告訴他存取的字符集是什么。 
PHP通過設置character_set_client,告訴Mysql,PHP存進數(shù)據(jù)庫的是什么編碼方式。
PHP通過設置character_set_results,告訴Mysql,PHP需要取什么樣編碼的數(shù)據(jù)。
PHP通過設置character_set_connection,告訴Mysql,PHP查詢中的文本,使用什么編碼。
MYSQL使用設置的編碼方式存儲文本。
假設Mysql使用setserver來存儲文本,PHP的character_set_client是setclient,PHP的 character_set_results是setresult。那么,Mysql將PHP發(fā)來的文本,從setclient編碼方式,轉(zhuǎn)換成 setserver編碼方式,再存入數(shù)據(jù)庫,如果PHP取文本,Mysql將文本從setserver轉(zhuǎn)換成setresult,再發(fā)送給PHP。
PHP文件(最終生成的HTML文件)本身有個編碼,如果Mysql傳過來的編碼,與PHP文件自身的編碼不同,那么,整個網(wǎng)頁,必然亂碼。所以,PHP一般將自己的編碼方式,告訴Mysql。
要保證不亂碼,就必須將三個編碼統(tǒng)一:一是網(wǎng)頁自身的編碼,二是HTML里指定的編碼,三是PHP告訴Mysql的編碼(包括character_set_client和character_set_results)。
第一和第二個編碼,如果使用DW之類的編輯器寫的網(wǎng)頁,通常是一致的,但用記事本寫的網(wǎng)頁,有可能不一致。(這里我感覺不太準確,需要討論一下)
第三個編碼,需要手工通知Mysql。這步可以通過在PHP里使用mysql_query(“set names characterX”)來實現(xiàn)。

d.字符集的轉(zhuǎn)換問題
如果小字集轉(zhuǎn)換成大字符集,不會丟失數(shù)據(jù),但大字集,轉(zhuǎn)換成小字集,可能會丟失數(shù)據(jù)。
比如,UTF8里有的字符,GB2312不一定有,所以,從UTF8轉(zhuǎn)換到GB2312可能會丟失一些字符。
但有種情況例外,先從GB2312轉(zhuǎn)成UTF8,再從UTF8轉(zhuǎn)成GB2312,這種情況是不會丟數(shù)據(jù)的,因為,剛開始轉(zhuǎn)換的文本,都是GB2312里的字符,所以,整個過程都是GB2312的字符在轉(zhuǎn)換,不會丟失。
正因為UTF8能容納世界上的所有字符,所以,數(shù)據(jù)庫一般使用UTF8編碼。這使得,任何字符都可以存進UTF8編碼的數(shù)據(jù)庫。

e. PHPMyAdmin亂碼的問題
PHPMyAdmin支持多國語言,這就必定要求HTML頁面使用UTF8編碼。
HTML頁面使用UTF8編碼,這就必定要求PHPMyAdmin連接Mysql時,character_set_client和character_set_results使用UTF8編碼。
當前情況下,PHP連接Mysql只能是使用set names(或其它幾個語句)來通知Mysql的編碼方式,如果沒有顯式的聲明編碼方式,都將使用latin1編碼。一般的程序,都沒有顯式聲明 character_set_client變量,所以,都是將gb2312文本,按latin1編碼方式存在數(shù)據(jù)庫,PHPMyAdmin再用utf8格式讀取,肯定是亂碼的。
如果PHP程序按正確的編碼存入數(shù)據(jù)庫,肯定是沒有問題的。所以,需要修改的不是PHPMyAdmin.(雖然有時修改PHPMyAdmin可以解決亂碼問題,但這不是問題的根本)