二、JAVA 對字符的處理
1. getBytes(charset)
這是 java 字符串處理的一個(gè)標(biāo)準(zhǔn)函數(shù),其作用是將字符串所表示的字符按照 charset 編碼,并以字節(jié)方式表示。注意字符串在 java 內(nèi)存中總是按 unicode 編碼存儲(chǔ)的。
當(dāng)Java程序從輸入流、文件或字符文字量等途徑獲得字符串時(shí),均會(huì)做字符編碼的轉(zhuǎn)換,例如InputStreamReader 的構(gòu)造函數(shù)中就需要指定編碼方式,而對于從文件和字符文字量中獲得字符串時(shí),均采用系統(tǒng)默認(rèn)的編碼方式對字符數(shù)據(jù)進(jìn)行解碼。考慮下面一段代碼:
String str=”中”; |
① |
byte[] bytes = str.getBytes(); |
② |
bytes = str.getBytes(“ISO-8859-1”); |
③ |
語句①:將一個(gè)只含有一個(gè)字符“中”的字符串文字量賦給 String 類的一個(gè)對象 str,字符文字量“中”是按照操作系統(tǒng)默認(rèn)編碼方式進(jìn)行編碼,在中文 windows 系統(tǒng)中通常是“GBK”,“中”在GBK編碼中是0xD6D0,在將該字符賦給str時(shí),Java會(huì)對該字符串進(jìn)行編碼轉(zhuǎn)換,即將GBK編碼方式的“中”轉(zhuǎn)換成Unicode編碼方式的“中”,Unicode編碼方式“中”的編碼是0x4E2D,所以str在程序運(yùn)行期間在內(nèi)存中的二進(jìn)制表示成16進(jìn)制就是0x4E2D。
語句②:獲得str字符串的二進(jìn)制形式。getBytes(String encoding)方法需要指定編碼方式,表示獲得該字符串在何種編碼方式中的二進(jìn)制形式。此語句中沒有設(shè)置參數(shù),表示采用操作系統(tǒng)默認(rèn)的編碼方式,即此處獲得的bytes是“中”在GBK編碼中的二進(jìn)制形式,即bytes[0]=0xD6, bytes[1]=0xD0。
語句③:該語句與語句②的區(qū)別就是指定了編碼方式,此處指定的是ISO-8859-1,即通常所說的Latin-1,該編碼采用8bit對字符編碼,所以編碼空間中只有256個(gè)字符。該編碼中只包含了基本的ASCII碼和一些擴(kuò)展的其它西歐字符,所以該字符集中不可能包含中文的“中”字,也就是說Java虛擬機(jī)無法在ISO-8859-1編碼集中找到“中”字對應(yīng)的編碼,針對這種情況,就只返回一個(gè)問號(?,0x3f)字符,所以此時(shí)bytes.length只有1,且bytes[0]=0x3f。
2.new String(byte[] bytes, String encoding)
getBytes()方法從字符串獲得二進(jìn)制的字節(jié)數(shù)組。如果要從二進(jìn)制的字節(jié)數(shù)組獲得字符串,則就需要使用new String(byte[] bytes, String encoding)方法,該方法按照encoding編碼方法對字節(jié)數(shù)組bytes中的二進(jìn)制數(shù)組進(jìn)行解析,生成一個(gè)新的字符串對象。
byte[] bytes = {(byte)0xD6, (byte)0xD0, (byte)0x31}; |
① |
String str = new String(bytes); |
② |
str = new String(bytes,”ISO-8859-1”); |
③ |
語句①:定義一個(gè)字節(jié)數(shù)組。
語句②:將該字節(jié)數(shù)組中的二進(jìn)制數(shù)據(jù)按照默認(rèn)的編碼方式(GBK)編碼成字符串,我們知道GBK中0xD6 0xD0表示“中”,0x31表示字符“1”(GBK兼容ASCII,但不兼容ISO-8859-1除ASCII之外的部分),所以str得到的值是“中1”。
語句③:該句用ISO-8859-1編碼方式對該字節(jié)數(shù)據(jù)進(jìn)行編碼,由于在ISO-8859-1編碼方式中一個(gè)字節(jié)會(huì)被解析成一個(gè)字符,所以該字節(jié)數(shù)組會(huì)被解釋成包含三個(gè)字符的字符串,但由于在ISO-8859-1編碼方式中沒有對應(yīng)0xD6和0xD0的字符,所以前兩個(gè)字符會(huì)產(chǎn)生兩個(gè)問號,由于0x31在ISO-8859-1編碼中對應(yīng)字符“1”(ISO-8859-1也兼容ASCII),所以此語句得到str的值是“??1”。
3.setCharacterEncoding()
該函數(shù)用來設(shè)置http請求或者相應(yīng)的編碼。
對于request,是指提交內(nèi)容的編碼,指定后可以通過getParameter()直接獲得正確的字符串,如果不指定,則默認(rèn)使用iso8859-1 編碼,需要進(jìn)一步處理。值得注意的是在執(zhí)行setCharacterEncoding()之前,不能執(zhí)行任何 getParameter()。而且,該指定只對POST方法有效,對GET方法無效。分析原因,應(yīng)該是在執(zhí)行第一個(gè)getParameter()的時(shí)候,java將會(huì)按照編碼分析所有的提交內(nèi)容,而后續(xù)的getParameter()不再進(jìn)行分析,所以setCharacterEncoding()無效。而對于GET方法提交表單時(shí),提交的內(nèi)容在URL中,一開始就已經(jīng)按照編碼分析所有的提交內(nèi)容,setCharacterEncoding()自然就無效。
對于response,則是指定輸出內(nèi)容的編碼,同時(shí),該設(shè)置會(huì)傳遞給瀏覽器,告訴瀏覽器輸出內(nèi)容所采用的編碼。
三、頁面編碼
頁面編碼主要有兩方面,一是頁面本身的編碼格式,即以什么編碼方式保存,二是客戶端瀏覽器以什么編碼格式顯示頁面。
1. 頁面保存編碼格式
1). HTML 頁面的編碼要看你保存文件時(shí)的編碼選項(xiàng),多數(shù)的網(wǎng)頁編輯軟件可以讓你選擇編碼的類型,默認(rèn)為本地編碼,為了使網(wǎng)頁減少編碼的問題,最好保存為 UTF-8 編碼格式。
2). JSP 頁面使用下列標(biāo)簽指定 JSP 源文件的編碼格式,具體來說,我們在JSP源文件頭上加入下面的一句即可:
<%@page pageEncoding="xxx"%>,xxx可以為GB2312,GBK,UTF-8(和MySQL不同,MySQL是 UTF8)等等,其默認(rèn)值為ISO-8859-1。保存文件時(shí)的編碼應(yīng)該與xxx 一致。
2. 頁面顯示編碼(通知客戶端瀏覽器用什么字符集編碼顯示頁面)
使用 <META http-equiv="content-type" content="text/html; charset=xxx"> 標(biāo)簽設(shè)置頁面顯示編碼
使用 response.setContentType("text/html; charset=xxx");來指定生成的頁面編碼。
使用 <%@ page language="java" contentType="text/html; charset=xxx"%> 設(shè)置頁面顯示編碼。字符集的默認(rèn)值為ISO-8859-1。
3. 頁面輸入編碼
在設(shè)置頁面顯示編碼的同時(shí),指定了頁面的輸入方式。如果沒有指定頁面編碼,則使用操作系統(tǒng)本身的默認(rèn)編碼。
四、表單傳遞參數(shù)編碼
使用表單輸入數(shù)據(jù)時(shí),處理過程如下:
User input *(gbk:d6d0 cec4)
browser *(gbk: d6d0 cec4)
web server iso8859-1(00d6 00d 000ce 00c4) class,需要在class中進(jìn)行處理:getbytes("iso8859-1")為d6 d0 ce c4,new String("gbk")為d6d0 cec4,內(nèi)存中以 unicode編碼則為4e2d 6587。
1.用戶輸入的編碼方式和頁面指定的編碼有關(guān)。
2.從 browser 到 web server,可以在表單中指定提交內(nèi)容時(shí)使用的字符集,否則會(huì)使用頁面指定的編碼。而如果在url中直接用 ? 的方式輸入?yún)?shù),則其編碼往往是操作系統(tǒng)本身的編碼,因?yàn)檫@時(shí)和頁面無關(guān)。
3. Web server接收到的是字節(jié)流,默認(rèn)時(shí)(getParameter)會(huì)以 iso8859-1編碼處理之,結(jié)果是不正確的,所以需要進(jìn)行處理。但如果預(yù)先設(shè)置了編碼(通過 request. setCharacterEncoding ()),則能夠直接獲取到正確的結(jié)果。