前言
漢語(yǔ)歪曲問題在我們的日常開發(fā)中很常見,那么雜亂的問題是如何產(chǎn)生的呢?又如何解決亂七八糟的問題?這篇文章將結(jié)合基本概念和例子來(lái)敘述,希望大家都有收獲。
一個(gè)簡(jiǎn)單亂碼的例子
package whx;
import java.io.UnsupportedEncodingException;
public class TestEncodeAndDecode {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "測(cè)試中文亂碼";
byte[] b = ("GBK");
Sy(new String (b,"UTF-8"));
}
}
復(fù)制代碼
用GBK編碼,用utf-8解碼,產(chǎn)生亂碼,運(yùn)行結(jié)果如下:
相關(guān)基礎(chǔ)概念
要理解亂碼的根源,需要先了解清楚位、字節(jié)、字符、字符集等相關(guān)概念。
位(bit)
位是計(jì)算機(jī)存儲(chǔ)數(shù)據(jù)的最小單位,1或者0就表示1位,如10010010就表示8位的二進(jìn)制數(shù)。
字節(jié)
字節(jié)是計(jì)算機(jī)信息技術(shù)用于計(jì)量存儲(chǔ)容量的一種計(jì)量單位,作為一個(gè)單位來(lái)處理的一個(gè)二進(jìn)制數(shù)字串,是構(gòu)成信息的一個(gè)小單位。
1 B = 8 bit (1字節(jié)等于8位)
1 KB = 1024 B = 1024 字節(jié)
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
復(fù)制代碼
字符
字符是指計(jì)算機(jī)中使用的字母、數(shù)字、字和符號(hào),是數(shù)據(jù)結(jié)構(gòu)中最小的數(shù)據(jù)存取單位。如a、A、B、b、大、+、*、%等都表示一個(gè)字符;
在 ASCII 編碼中,一個(gè)英文字母字符存儲(chǔ)需要1個(gè)字節(jié)。
在 GB 2312 編碼或 GBK編碼中,一個(gè)漢字字符存儲(chǔ)需要2個(gè)字節(jié)。
在UTF-8編碼中,一個(gè)英文字母字符存儲(chǔ)需要1個(gè)字節(jié),一個(gè)漢字字符儲(chǔ)存需要3到4個(gè)字節(jié)。
在UTF-16編碼中,一個(gè)英文字母字符或一個(gè)漢字字符存儲(chǔ)都需要2個(gè)字節(jié)
在UTF-32編碼中,世界上任何字符的存儲(chǔ)都需要4個(gè)字節(jié)
復(fù)制代碼
字符集
字符集是多個(gè)字符的集合,字符集種類較多,每個(gè)字符集包含的字符個(gè)數(shù)不同。常見字符集名稱:
ASCII字符集
GB2312字符集
Unicode字符集
復(fù)制代碼
編碼、解碼
計(jì)算機(jī)只認(rèn)識(shí)二進(jìn)制的1和0,而人類都是有自己的語(yǔ)言的,雙方要能進(jìn)行信息交流,必須要有從文字到0、1的轉(zhuǎn)化,以及0、1到文字轉(zhuǎn)化。
編碼: 就是將文本字符轉(zhuǎn)換成計(jì)算機(jī)可以識(shí)別的0、1機(jī)器碼。
解碼: 將存儲(chǔ)在計(jì)算機(jī)中的二進(jìn)制數(shù)解析成文字、字符。
常見字符集及其編碼方式
常見字符集有ASCII、GBK、Unicode等
ASCII字符集
ASCII字符集:它包括英文字母、阿拉伯?dāng)?shù)字和西文符號(hào)等可顯示字符,以及回車鍵、退格等控制字符。
ASCII 編碼:它是美國(guó)制定的字符編碼,用于將英語(yǔ)字符轉(zhuǎn)化為二進(jìn)制,規(guī)定了128個(gè)字符的編碼。
GBXXXX字符集
GBXXXX系列包括GB2312、GBK、GB18030,適用于漢字處理、漢字通信等系統(tǒng)之間的信息交換。
GB2312
- 全稱是《信息交換用漢字編碼字符集》,支持六千多漢字。
- 國(guó)家簡(jiǎn)體中文字符集,兼容ASCII,中國(guó)大陸和新加坡都采用此編碼。
- 每個(gè)漢字及符號(hào)以兩個(gè)字節(jié)來(lái)表示。
- 高字節(jié)從A1~F7, 低字節(jié)從A1~FE。將高字節(jié)和低字節(jié)分別加上0XA0即可得到編碼。
GBK
- GBK全稱《漢字內(nèi)碼擴(kuò)展規(guī)范》,擴(kuò)展了GB2312,加入對(duì)繁體字的支持,支持兩萬(wàn)多漢字。
- 每個(gè)漢字及符號(hào)也是以兩個(gè)字節(jié)來(lái)表示。
- 高字節(jié)從81~FE,低字節(jié)從40~FE。
GB18030
- GB 18030,全稱《信息技術(shù) 中文編碼字符集》,與GB2312、GBK編碼兼容,可支持27484個(gè)文字
- 采用變長(zhǎng)多字節(jié)編碼,每個(gè)字可以由1個(gè)、2個(gè)或4個(gè)字節(jié)組成。
- 1字節(jié)從00~7F; 2字節(jié)高字節(jié)從81~FE,低字節(jié)從40到7E和80到FE;4字節(jié)第一三字節(jié)從81~FE,第二四字節(jié)從30~39。
Unicode 字符集
Unicode是國(guó)際組織制定的可以容納世界上所有文字和符號(hào)的字符編碼方案。UNICODE字符集有多種編碼方式,分別是UTF-8,UTF-16和UTF-32。
UTF-8
- 是針對(duì)Unicode的一種可變長(zhǎng)度字符編碼。
- 它可以用來(lái)表示Unicode標(biāo)準(zhǔn)中的任何字符,而且其編碼中的第一個(gè)字節(jié)仍與ASCII相容,使得原來(lái)處理ASCII字符的軟件無(wú)須或只進(jìn)行少部份修改后,便可繼續(xù)使用。
- UTF-8使用1~4字節(jié)為每個(gè)字符編碼(ASCIl字符只需1字節(jié)編碼, 拉丁文、希臘文等需要兩個(gè)字節(jié)編碼, 中日韓文字使用三字節(jié)編碼, 其他極少使用的語(yǔ)言字符使用4字節(jié)編碼號(hào))
UTF-16
- 把Unicode字符集的抽象碼位映射為16位長(zhǎng)的整數(shù)(即碼元)的序列,用于數(shù)據(jù)存儲(chǔ)或傳遞。
- UTF-16比起UTF-8,好處在于大部分字符都以固定長(zhǎng)度的字節(jié) (2字節(jié)) 儲(chǔ)存,但UTF-16卻無(wú)法兼容于ASCII編碼。
UTF-32
- 一種將Unicode字符編碼的協(xié)定,對(duì)每一個(gè)Unicode碼位使用恰好32位元,其它的 Unicode 編碼方式則使用不定長(zhǎng)度編碼。
- 采用4字節(jié)編碼,處理速度比較快,但是浪費(fèi)空間,傳輸速度慢。
一個(gè)例子理解編碼解碼的廬山面目
我們敲代碼的程序員,接觸最多的就是“hello word”。計(jì)算機(jī)只認(rèn)識(shí)0和1,它是怎么展示hello word的呢?
上一小節(jié),我們已經(jīng)知道編碼、字符集的知識(shí)。我們可以用ASCII編碼,把“hello word”翻譯成計(jì)算機(jī)認(rèn)識(shí)的0、1。有興趣的朋友可以去查一下 ASCII對(duì)照表
計(jì)算機(jī)存儲(chǔ)的是hello world的0、1二進(jìn)制碼,先將二進(jìn)制碼解碼成對(duì)應(yīng)的字符,然后在屏幕上渲染出來(lái),我們看到的就是hello world了
亂碼如何產(chǎn)生的呢?
亂碼產(chǎn)生的原因主要有兩個(gè),一是文本字符編碼過程與解碼過程使用了不同的編碼方式,二是使用了缺少某種字體庫(kù)的字符集引起的亂碼。
編碼與解碼使用了不同的編碼方式
例子中,用了utf-8編碼,使用了GBK解碼,結(jié)果產(chǎn)生了亂碼。因?yàn)樵趗tf-8中,一個(gè)漢字用三個(gè)字節(jié)編碼,而GBK中,每個(gè)漢字用兩個(gè)字節(jié)表示,所以產(chǎn)生了亂碼。
使用了缺少某種字體庫(kù)的字符集
我們知道GB2312是不支持繁體字的,所以使用缺少某種字體庫(kù)的字符集編碼,會(huì)產(chǎn)生亂碼。
亂碼又如何解決呢
使用支持要展示字體的字符集編碼,并且編解碼使用同一種編碼方式,就可以解決亂碼問題了。
接下來(lái)列舉一下亂碼的經(jīng)典場(chǎng)景與解決方案
IntelliJ Idea亂碼問題
IDE項(xiàng)目中的中文亂碼問題?File->settings->Editor->File Encodings,設(shè)置一下編碼方式utf-8
IDE控制臺(tái)中文亂碼?嘗試一下這種方式,打開IDE安裝目錄,找到
在文本末尾添加-D
數(shù)據(jù)庫(kù)亂碼問題
查看數(shù)據(jù)庫(kù)編碼:
show variables like 'character_set%'
復(fù)制代碼
設(shè)置session、global范圍的編碼方式
//session 范圍
set character_set_server=utf8;
set character_set_database=utf8;
//global 范圍
set global character_set_database=utf8;
set global character_set_server=utf8;
復(fù)制代碼
session、global范圍編碼,重啟mysql可能編碼又變回去了,可以嘗試另外一種方式。在mysql(windows環(huán)境)的my.ini配置文件中修改或添加下列內(nèi)容
[mysql]
default-character-set=utf8
[mysqld]
default-character-set=utf8
[client]
default-character-set=utf8
復(fù)制代碼
編碼角度的亂碼問題
寫代碼的時(shí)候出現(xiàn)中文亂碼?追蹤定位到編碼解碼的地方,設(shè)置用同一種編碼方式。
寫在最后
需更加深入學(xué)習(xí)java知識(shí)的小伙伴以及即將參加面試的小伙伴可以購(gòu)買以下教程哦!
1.《寫代碼總是莫名其妙的亂碼?這一篇教你從原理出發(fā)徹底干掉它》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀點(diǎn),與本網(wǎng)站無(wú)關(guān),侵刪請(qǐng)聯(lián)系頁(yè)腳下方聯(lián)系方式。
2.《寫代碼總是莫名其妙的亂碼?這一篇教你從原理出發(fā)徹底干掉它》僅供讀者參考,本網(wǎng)站未對(duì)該內(nèi)容進(jìn)行證實(shí),對(duì)其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。
3.文章轉(zhuǎn)載時(shí)請(qǐng)保留本站內(nèi)容來(lái)源地址,http://f99ss.com/gl/3039293.html